Repository: blocksense-network/blocksense
Pull request #1203: feat(oracles): Gecko terminal oracle improved to uses less queries
Author: login: yordanmadzhunkov
Labels: name: area:oracle-scripts
description: Tasks related to our oracle scripts
Created: 2025-04-10T10:48:11Z | Merged: 2025-04-11T11:55:54Z

Starting oracle component - Gecko Terminal

```
🕛 All prices fetched in 2.352527903s
+---------+---------------+--------------------+---------+-------------------+------------------+---------------+
| Feed ID |    Network    |        Name        | Reverse |    Price[USD]     |   Volume[USD]    | Enough volume |
+---------+---------------+--------------------+---------+-------------------+------------------+---------------+
| 1000000 | monad-testnet | USDC / WMON        | true    |  9.31763032367082 | 969528.057604211 |           Yes |
| 1000000 | monad-testnet | USDT / WMON 0.2%   | true    |  9.31763032367082 | 14046.0923159966 |            No |
| 1000000 | monad-testnet | USDC / WMON        | true    |  9.31643796272197 | 917930.342558085 |           Yes |
| 1000000 | monad-testnet | DAK / WMON         | true    |  9.31763032367082 | 232138.989769562 |            No |
| 1000000 | monad-testnet | YAKI / WMON        | true    |  9.31763032367082 | 217604.335973354 |            No |
| 1000000 | monad-testnet | CHOG / WMON        | true    |  9.31763032367082 | 216774.123064113 |            No |
| 1000000 | monad-testnet | MAD / WMON         | true    |  9.31763032367082 | 900329.614808609 |           Yes |
| 1000000 | monad-testnet | BEAN / WMON        | true    |  9.31763032367082 | 234849.958209435 |            No |
| 1000000 | monad-testnet | USDC / WMON 0.2%   | true    |  9.30274970697553 | 76663.0748180967 |            No |
| 1000000 | monad-testnet | JAI / WMON         | true    |  9.31763032367082 | 111198.344447132 |            No |
|         |               |                    |         |                   |                  |               |
| 1000001 | base          | USDz / WETH 0.04%  | false   | 0.983863547600749 | 19473.6923211044 |           Yes |
| 1000001 | base          | USDz / USDC        | false   | 0.985468577802239 |   300.3308710499 |            No |
| 1000001 | base          | USDz / USDC 0.01%  | false   | 0.985754073657306 |   123.1643468033 |            No |
| 1000001 | base          | USDz / sUSDz 0.05% | false   | 0.986836521258986 |  2741.2708030979 |            No |
| 1000001 | base          | USDz / DOLA        | false   | 0.982871479093592 |    31.5053509551 |            No |
| 1000001 | base          | USDz / USDC 0.01%  | false   | 0.981834489999348 |  26895.239828666 |           Yes |
| 1000001 | base          | USDz / WETH        | false   | 0.984328055840613 |  2035.8595485847 |            No |
| 1000001 | base          | USDz / USDC 0.25%  | false   | 0.982729210150441 |   349.8518755227 |            No |
| 1000001 | base          | USDz / USD+ 0.01%  | false   | 0.979322347933539 |  4327.9163627207 |            No |
| 1000001 | base          | USDz / KEYCAT 0.3% | false   | 0.982136983346083 |  2499.9692929851 |            No |
|         |               |                    |         |                   |                  |               |
| 1000002 | base          | USR / USDC         | false   | 0.999585601888855 | 242814.526102816 |            No |
| 1000002 | base          | USR / GYD 0.01%    | false   |  1.00080077596886 | 211481.132239476 |            No |
| 1000002 | base          | USR / USDC 0.01%   | false   | 0.999863572267294 | 1299788.30490345 |           Yes |
| 1000002 | eth           | USR / USDC         | false   | 0.998626314312647 | 2837762.09843029 |           Yes |
| 1000002 | eth           | USR / RLP          | false   | 0.991961541895626 | 506544.586658851 |           Yes |
| 1000002 | eth           | USR / USDC 0.05%   | false   | 0.999006398676271 | 114860.937172711 |            No |
| 1000002 | eth           | USR / GYD 0.02%    | false   | 0.999498671317123 |   499.9248209197 |            No |
| 1000002 | eth           | GHO / USR          | true    | 0.991794990391365 | 4486029.43449032 |           Yes |
| 1000002 | eth           | DOLA / USR         | true    | 0.993164482411675 | 943392.954592892 |           Yes |
| 1000002 | eth           | yUSD / USR         | true    |  1.00005112330925 |   461.7321121724 |            No |
+---------+---------------+--------------------+---------+-------------------+------------------+---------------+
+---------+----------+-------------------------------+------------+
| Feed ID |   Name   |             Value             | Used Pools |
+---------+----------+-------------------------------+------------+
| 1000000 | WMON/USD |  Numerical(9.317237716955978) |          3 |
| 1000001 | USDZ/USD | Numerical(0.9826866390914135) |          2 |
| 1000002 | USR/USD  | Numerical(0.9948971298105642) |          5 |
+---------+----------+-------------------------------+------------+

```


Diff:
diff --git a/apps/oracles/gecko-terminal/spin.toml b/apps/oracles/gecko-terminal/spin.toml
index f3a4772b88..5cbf1e3399 100644
--- a/apps/oracles/gecko-terminal/spin.toml
+++ b/apps/oracles/gecko-terminal/spin.toml
@@ -16,20 +16,20 @@ component = "gecko-terminal"
 
 [[trigger.oracle.data_feeds]]
 id = "1000000"
-data = '{"pair":{"base":"WMON","quote":"USD"},"decimals":8,"category":"Crypto","market_hours":"Crypto","arguments":[{"network":"monad-testnet","pool":"0x264e9b75723d75e3c607627d8e21d2c758db4c80","reverse":true},{"network":"monad-testnet","pool":"0x8552706d9a27013f20ea0f9df8e20b61e283d2d3","reverse":true},{"network":"monad-testnet","pool":"0x5323821de342c56b80c99fbc7cd725f2da8eb87b","reverse":true},{"network":"monad-testnet","pool":"0x6e4b7be5ef7f8950c76baa0bd90125bc9b33c8db","reverse":true},{"network":"monad-testnet","pool":"0x212fde77a42d55f980d0a0304e7eebe1e999c60f","reverse":true},{"network":"monad-testnet","pool":"0xc0ce32eee0eb8bf24fa2b00923a78abc5002f91e","reverse":true},{"network":"monad-testnet","pool":"0x786f4aa162457ecdf8fa4657759fa3e86c9394ff","reverse":true},{"network":"monad-testnet","pool":"0xf2afc5aa9965cdb2d4be94823c98411291b61297","reverse":true},{"network":"monad-testnet","pool":"0xf22d36b6bee8a7fd51def4e3badf35a8733b284f","reverse":true},{"network":"monad-testnet","pool":"0xe8a806ae6ecb1f02063e21c6f0579b145399ee5f","reverse":true}]}'
+data = '{"pair":{"base":"WMON","quote":"USD"},"decimals":8,"category":"Crypto","market_hours":"Crypto","arguments":[{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x264e9b75723d75e3c607627d8e21d2c758db4c80","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x8552706d9a27013f20ea0f9df8e20b61e283d2d3","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x5323821de342c56b80c99fbc7cd725f2da8eb87b","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x6e4b7be5ef7f8950c76baa0bd90125bc9b33c8db","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x212fde77a42d55f980d0a0304e7eebe1e999c60f","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0xc0ce32eee0eb8bf24fa2b00923a78abc5002f91e","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x786f4aa162457ecdf8fa4657759fa3e86c9394ff","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0xf2afc5aa9965cdb2d4be94823c98411291b61297","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0xf22d36b6bee8a7fd51def4e3badf35a8733b284f","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0xe8a806ae6ecb1f02063e21c6f0579b145399ee5f","reverse":true}]}'
 
 [[trigger.oracle.data_feeds]]
 id = "1000001"
-data = '{"pair":{"base":"USDZ","quote":"USD"},"decimals":8,"category":"Crypto","market_hours":"Crypto","arguments":[{"network":"base","pool":"0xcf88b8bf7ccce2d836878e538197eb20fc673bce","reverse":false},{"network":"base","pool":"0x6d0b9c9e92a3de30081563c3657b5258b3ffa38b","reverse":false},{"network":"base","pool":"0xebf0e4da26a0d040c2343a9e072a0d0b8cf1e0b0","reverse":false},{"network":"base","pool":"0x96cc4b6a75fa1dfea66091589d1f25aff3aa0318","reverse":false},{"network":"base","pool":"0xcea8ef6ce6235f2c2cdd13c9e8a3ed470725a638","reverse":false},{"network":"base","pool":"0xde5ff829fef54d1bdec957d9538a306f0ead1368","reverse":false},{"network":"base","pool":"0x2ce63497999f520cc2afaaadbcfc37afd9def4b0","reverse":false},{"network":"base","pool":"0xe722e6bce1a598e6b5d26e9975bf44140d2aa3e5","reverse":false},{"network":"base","pool":"0x4ef1e503c4f1e5664ac98294d0e42ddc9c0ff961","reverse":false},{"network":"base","pool":"0x2c206c7de24787f85b5c52d2ea339adc6d5af40f","reverse":false}]}'
+data = '{"pair":{"base":"USDZ","quote":"USD"},"decimals":8,"category":"Crypto","market_hours":"Crypto","arguments":[{"min_volume_usd":10000.0,"network":"base","pool":"0xcf88b8bf7ccce2d836878e538197eb20fc673bce","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0x6d0b9c9e92a3de30081563c3657b5258b3ffa38b","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0xebf0e4da26a0d040c2343a9e072a0d0b8cf1e0b0","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0x96cc4b6a75fa1dfea66091589d1f25aff3aa0318","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0xcea8ef6ce6235f2c2cdd13c9e8a3ed470725a638","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0xde5ff829fef54d1bdec957d9538a306f0ead1368","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0x2ce63497999f520cc2afaaadbcfc37afd9def4b0","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0xe722e6bce1a598e6b5d26e9975bf44140d2aa3e5","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0x4ef1e503c4f1e5664ac98294d0e42ddc9c0ff961","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0x2c206c7de24787f85b5c52d2ea339adc6d5af40f","reverse":false}]}'
 
 [[trigger.oracle.data_feeds]]
 id = "1000002"
-data = '{"pair":{"base":"USR","quote":"USD"},"decimals":8,"category":"Crypto","market_hours":"Crypto","arguments":[{"network":"base","pool":"0xd3ee0a3b349237d68517df30bfb66be971f46ad9","reverse":false},{"network":"base","pool":"0xb924561a57fc60041414b8471cbc99d3497097fa","reverse":false},{"network":"base","pool":"0x97c9750305a39e06002edd851f3d37a862ac7060","reverse":false},{"network":"eth","pool":"0x3ee841f47947fefbe510366e4bbb49e145484195","reverse":false},{"network":"eth","pool":"0xc907ba505c2e1cbc4658c395d4a2c7e6d2c32656","reverse":false},{"network":"eth","pool":"0x8bb9cd887dd51c5aa8d7da9e244c94bec035e47c","reverse":false},{"network":"eth","pool":"0x8461537a9bfc5a1df57cf825f8a58049ef61557b","reverse":false},{"network":"eth","pool":"0x4628f13651ead6793f8d838b34b8f8522fb0cc52","reverse":true},{"network":"eth","pool":"0x38de22a3175708d45e7c7c64cd78479c8b56f76e","reverse":true},{"network":"eth","pool":"0xd552716f3bba4224a19d7eb37a31650d7ae10144","reverse":true}]}'
+data = '{"pair":{"base":"USR","quote":"USD"},"decimals":8,"category":"Crypto","market_hours":"Crypto","arguments":[{"min_volume_usd":500000.0,"network":"base","pool":"0xd3ee0a3b349237d68517df30bfb66be971f46ad9","reverse":false},{"min_volume_usd":500000.0,"network":"base","pool":"0xb924561a57fc60041414b8471cbc99d3497097fa","reverse":false},{"min_volume_usd":500000.0,"network":"base","pool":"0x97c9750305a39e06002edd851f3d37a862ac7060","reverse":false},{"min_volume_usd":500000.0,"network":"eth","pool":"0x3ee841f47947fefbe510366e4bbb49e145484195","reverse":false},{"min_volume_usd":500000.0,"network":"eth","pool":"0xc907ba505c2e1cbc4658c395d4a2c7e6d2c32656","reverse":false},{"min_volume_usd":500000.0,"network":"eth","pool":"0x8bb9cd887dd51c5aa8d7da9e244c94bec035e47c","reverse":false},{"min_volume_usd":500000.0,"network":"eth","pool":"0x8461537a9bfc5a1df57cf825f8a58049ef61557b","reverse":false},{"min_volume_usd":500000.0,"network":"eth","pool":"0x4628f13651ead6793f8d838b34b8f8522fb0cc52","reverse":true},{"min_volume_usd":500000.0,"network":"eth","pool":"0x38de22a3175708d45e7c7c64cd78479c8b56f76e","reverse":true},{"min_volume_usd":500000.0,"network":"eth","pool":"0xd552716f3bba4224a19d7eb37a31650d7ae10144","reverse":true}]}'
 
 [component.gecko-terminal]
 source = "../../../target/wasm32-wasip1/release/gecko_terminal.wasm"
 
-allowed_outbound_hosts = ["https://app.geckoterminal.com/"]
+allowed_outbound_hosts = ["https://api.geckoterminal.com"]
 
 [component.gecko-terminal.build]
 command = "cargo build --target wasm32-wasip1 --release"
diff --git a/apps/oracles/gecko-terminal/src/lib.rs b/apps/oracles/gecko-terminal/src/lib.rs
index 6cc94350a5..6d55e980e6 100644
--- a/apps/oracles/gecko-terminal/src/lib.rs
+++ b/apps/oracles/gecko-terminal/src/lib.rs
@@ -1,160 +1,273 @@
 use std::collections::HashMap;
 
 use anyhow::{Context, Result};
+use blocksense_sdk::http::http_get_json;
 use blocksense_sdk::{
     oracle::{DataFeedResult, DataFeedResultValue, Payload, Settings},
     oracle_component,
-    spin::http::{send, Method, Request, Response},
 };
+
 use prettytable::{format, Cell, Row, Table};
 use serde::{Deserialize, Serialize};
 use serde_this_or_that::as_f64;
+use std::time::Instant;
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
+    #[serde(deserialize_with = "as_f64")]
+    pub base_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub h6: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct ResponseData {
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
+    pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct GeckoTerminalData {
-    pub id: String,
-    pub attributes: PoolAttributes,
+pub struct GeckoTerminalResponce {
+    pub data: ResponseData,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct GeckoTerminalResponce {
-    pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<ResponseData>,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+type GeckoTerminalDataForFeed = HashMap<String, Vec<ResponseData>>;
 
+impl ResponseData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
         } else {
-            self.data.attributes.price_in_usd
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn check_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
+        } else {
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
-pub struct GeckoTerminalPool {
+pub struct GeckoTerminalFeedConfig {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_pools_data_for_network(
+    network: &String,
+    pools: &[GeckoTerminalFeedConfig],
+) -> Result<GeckoTerminalMultipleResponce> {
+    let r = pools
+        .iter()
+        .map(|p| p.pool.clone())
+        .collect::<Vec<_>>()
+        .join(",");
+    let url = format!("https://api.geckoterminal.com/api/v2/networks/{network}/pools/multi/{r}");
+
+    let mut value = http_get_json::<GeckoTerminalMultipleResponce>(&url, None).await?;
+    for v in value.data.iter_mut() {
+        if let Some(p) = pools
+            .iter()
+            .find(|p| p.pool.to_uppercase() == v.attributes.address.to_uppercase())
+        {
+            v.reverse = p.reverse;
+            v.feed_id = p.feed_id.clone();
+            v.network = network.clone();
+            v.min_volume_usd = p.min_volume_usd;
+        }
     }
+    Ok(value)
 }
 
-async fn fetch_all_prices(
-    resourses: &Vec<FeedConfig>,
-) -> Result<HashMap<String, Vec<GeckoTerminalResponce>>> {
-    let mut res = HashMap::new();
-    for config in resourses {
-        let mut v = vec![];
-        for pool in config.arguments.iter() {
-            match pool.fetch().await {
-                Ok(response) => {
-                    v.push(response);
-                }
-                Err(e) => {
-                    println!("Error {e:?} when fetching from {pool:?}");
-                }
-            };
+async fn fetch_all_prices(resources: &Vec<FeedConfig>) -> Result<GeckoTerminalDataForFeed> {
+    let pools_by_network = group_pools_by_network(resources);
+
+    let before_fetch = Instant::now();
+    let mut res = GeckoTerminalDataForFeed::new();
+    for network in pools_by_network.keys() {
+        if let Some(pools) = pools_by_network.get(network) {
+            for pools in pools.chunks(50) {
+                let response = fetch_pools_data_for_network(network, pools).await;
+                match response {
+                    Ok(re) => {
+                        for d in re.data {
+                            res.entry(d.feed_id.clone()).or_default().push(d);
+                        }
+                    }
+                    Err(err) => {
+                        let pools_addresses = pools
+                            .iter()
+                            .map(|x| x.pool.to_string())
+                            .collect::<Vec<String>>()
+                            .join(",");
+                        println!("❌ Error fetching prices from network for {network}: {err:?}. Pools {pools_addresses}");
+                    }
+                };
+            }
         }
-        res.insert(config.id.clone(), v);
     }
+
+    println!("🕛 All prices fetched in {:?}", before_fetch.elapsed());
     Ok(res)
 }
 
-fn process_results(reponses: &HashMap<String, Vec<GeckoTerminalResponce>>) -> Result<Payload> {
+fn group_pools_by_network(
+    resources: &Vec<FeedConfig>,
+) -> HashMap<String, Vec<GeckoTerminalFeedConfig>> {
+    let mut pools_by_network: HashMap<String, Vec<GeckoTerminalFeedConfig>> = HashMap::new();
+    for config in resources {
+        for pool in &config.arguments {
+            let new_pool = {
+                let mut cloned_pool = pool.clone();
+                cloned_pool.feed_id = config.id.clone();
+                cloned_pool
+            };
+            pools_by_network
+                .entry(pool.network.clone())
+                .or_default()
+                .push(new_pool);
+        }
+    }
+    pools_by_network
+}
+fn process_results(reponses: &GeckoTerminalDataForFeed) -> Result<Payload> {
     let mut payload: Payload = Payload::new();
-    for (id, responses) in reponses.iter() {
+    for (id, vec_data) in reponses.iter() {
         let mut total: f64 = 0.0f64;
         let mut total_weight: f64 = 0.0f64;
         let mut total_weighted_price: f64 = 0.0f64;
         let mut count: i32 = 0;
-        for response in responses {
-            let price = response.get_price();
-            let weight = response
-                .data
-                .attributes
-                .historical_data
-                .last_24h
-                .volume_in_usd;
-            total += price;
-            total_weighted_price += price * weight;
-            total_weight += weight;
-            count += 1;
+        for data in vec_data {
+            if data.check_volume_usd() {
+                let price = data.get_price();
+                let weight = data.attributes.volume_usd.h24;
+                total += price;
+                total_weighted_price += price * weight;
+                total_weight += weight;
+                count += 1;
+            }
         }
-        let price = if count == 1 {
-            total
+        if count > 0 {
+            let price = if count == 1 {
+                total
+            } else {
+                total_weighted_price / total_weight
+            };
+            payload.values.push(DataFeedResult {
+                id: id.clone(),
+                value: DataFeedResultValue::Numerical(price),
+            });
         } else {
-            total_weighted_price / total_weight
-        };
-        payload.values.push(DataFeedResult {
-            id: id.clone(),
-            value: DataFeedResultValue::Numerical(price),
-        });
+            payload.values.push(DataFeedResult {
+                id: id.clone(),
+                value: DataFeedResultValue::Error(
+                    "Not enough volume to reliably average prices".to_string(),
+                ),
+            });
+        }
     }
     Ok(payload)
 }
 
+fn print_responses(reponses: &GeckoTerminalDataForFeed) {
+    let mut table = Table::new();
+    table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
+
+    table.set_titles(Row::new(vec![
+        Cell::new("Feed ID").style_spec("bc"),
+        Cell::new("Network").style_spec("bc"),
+        Cell::new("Name").style_spec("bc"),
+        Cell::new("Reverse").style_spec("bc"),
+        Cell::new("Price[USD]").style_spec("bc"),
+        Cell::new("Volume[USD]").style_spec("bc"),
+        Cell::new("Enough volume").style_spec("bc"),
+    ]));
+    let mut first_row = true;
+    let mut feed_ids = reponses.keys().cloned().collect::<Vec<String>>();
+    feed_ids.sort();
+    for feed_id in feed_ids {
+        if let Some(data) = reponses.get(&feed_id) {
+            if !first_row {
+                table.add_empty_row();
+            } else {
+                first_row = false;
+            }
+            for d in data {
+                let price = d.get_price();
+                let enough_volume = if d.check_volume_usd() {
+                    "Yes".to_string()
+                } else {
+                    "No".to_string()
+                };
+                table.add_row(Row::new(vec![
+                    Cell::new(&d.feed_id).style_spec("r"),
+                    Cell::new(&d.network).style_spec("l"),
+                    Cell::new(&d.attributes.name).style_spec("l"),
+                    Cell::new(&d.reverse.to_string()).style_spec("l"),
+                    Cell::new(&price.to_string()).style_spec("r"),
+                    Cell::new(&d.attributes.volume_usd.h24.to_string()).style_spec("r"),
+                    Cell::new(&enough_volume).style_spec("r"),
+                ]));
+            }
+        }
+    }
+    table.printstd();
+}
+
 fn print_results(
-    resourses: &[FeedConfig],
-    reponses: &HashMap<String, Vec<GeckoTerminalResponce>>,
+    resources: &[FeedConfig],
+    responses: &GeckoTerminalDataForFeed,
     payload: &Payload,
 ) {
+    print_responses(responses);
+
     let mut table = Table::new();
     table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
 
@@ -162,25 +275,36 @@ fn print_results(
         Cell::new("Feed ID").style_spec("bc"),
         Cell::new("Name").style_spec("bc"),
         Cell::new("Value").style_spec("bc"),
-        Cell::new("Num Pools").style_spec("bc"),
+        Cell::new("Used Pools").style_spec("bc"),
     ]));
 
-    for (id, responses) in reponses.iter() {
-        if let Some(resourse) = resourses.iter().find(|x| x.id == *id) {
-            let name = format!("{}/{}", resourse.pair.base, resourse.pair.quote);
-            if let Some(result) = payload.values.iter().find(|x| x.id == *id) {
-                let value = format!("{:?}", result.value);
-                let num_pools = format!("{}", responses.len());
-                table.add_row(Row::new(vec![
-                    Cell::new(&id.to_string()).style_spec("r"),
-                    Cell::new(&name).style_spec("l"),
-                    Cell::new(&value).style_spec("r"),
-                    Cell::new(&num_pools).style_spec("r"),
-                ]));
-            }
+    let mut feed_ids = responses.keys().cloned().collect::<Vec<String>>();
+    feed_ids.sort();
+    for feed_id in feed_ids {
+        let name = if let Some(resourse) = resources.iter().find(|x| x.id == feed_id) {
+            format!("{}/{}", resourse.pair.base, resourse.pair.quote)
+        } else {
+            "No name".to_string()
+        };
+        let num_pools = if let Some(feed_id_responses) = responses.get(&feed_id) {
+            feed_id_responses
+                .iter()
+                .filter(|x| x.check_volume_usd())
+                .count()
+                .to_string()
+        } else {
+            "No response".to_string()
+        };
+        if let Some(result) = payload.values.iter().find(|x| x.id == *feed_id) {
+            let value = format!("{:?}", result.value);
+            table.add_row(Row::new(vec![
+                Cell::new(&feed_id.to_string()).style_spec("r"),
+                Cell::new(&name).style_spec("l"),
+                Cell::new(&value).style_spec("r"),
+                Cell::new(&num_pools).style_spec("r"),
+            ]));
         }
     }
-
     table.printstd();
 }
 
@@ -197,7 +321,7 @@ async fn oracle_request(settings: Settings) -> Result<Payload> {
 #[derive(Deserialize, Debug)]
 struct FeedArgumentsVec {
     pub pair: Pair,
-    pub arguments: Vec<GeckoTerminalPool>,
+    pub arguments: Vec<GeckoTerminalFeedConfig>,
 }
 
 #[derive(Deserialize, Debug)]
@@ -209,7 +333,7 @@ pub struct Pair {
 #[derive(Deserialize, Debug)]
 struct FeedConfig {
     pub id: String,
-    pub arguments: Vec<GeckoTerminalPool>,
+    pub arguments: Vec<GeckoTerminalFeedConfig>,
     pub pair: Pair,
 }
 
@@ -233,351 +357,999 @@ fn get_resources_from_settings(settings: &Settings) -> Result<Vec<FeedConfig>> {
 
 #[cfg(test)]
 mod tests {
-    use crate::GeckoTerminalResponce;
+    use crate::GeckoTerminalMultipleResponce;
     #[test]
     fn test_parsing_responce() {
         let raw = r#"{
-            "data":{
-                "id":"171227265",
-                "type":"pool",
-                "attributes":{
-                    "address":"0x8552706d9a27013f20ea0f9df8e20b61e283d2d3",
-                    "name":"USDT / WMON 0.2%",
-                    "fully_diluted_valuation":"1817838994588.86",
-                    "base_token_id":"38534023",
-                    "price_in_usd":"181.783899458886",
-                    "price_in_target_token":"10.0009767679",
-                    "reserve_in_usd":"1308999961.9237",
-                    "reserve_threshold_met":true,
-                    "from_volume_in_usd":"50075.0824436682",
-                    "to_volume_in_usd":"50075.0824436682",
-                    "api_address":"0x8552706d9a27013f20ea0f9df8e20b61e283d2d3",
-                    "pool_fee":"0.2%",
-                    "token_weightages":null,
-                    "token_reserves":{
-                        "38534023":{
-                            "reserves":"7197341.24226823",
-                            "reserves_in_usd":1308369509.3935878
-                        },
-                        "38379114":{
-                            "reserves":"33411.1466004131",
-                            "reserves_in_usd":607305.5948889041
-                        }
-                    },
-                    "token_value_data":{
-                        "38534023":{
-                            "fdv_in_usd":1817851155520.9482,
-                            "market_cap_in_usd":null,
-                            "market_cap_to_holders_ratio":null
-                        },
-                        "38379114":{
-                            "fdv_in_usd":1840830347.322756,
-                            "market_cap_in_usd":null,
-                            "market_cap_to_holders_ratio":null
-                        }
+            "data": [
+              {
+                "id": "monad-testnet_0xc0ce32eee0eb8bf24fa2b00923a78abc5002f91e",
+                "type": "pool",
+                "attributes": {
+                  "base_token_price_usd": "0.163828268957235",
+                  "base_token_price_native_currency": "0.0168950585423778",
+                  "quote_token_price_usd": "9.66558346381163",
+                  "quote_token_price_native_currency": "1.0",
+                  "base_token_price_quote_token": "0.01689505854",
+                  "quote_token_price_base_token": "59.18890411",
+                  "address": "0xc0ce32eee0eb8bf24fa2b00923a78abc5002f91e",
+                  "name": "CHOG / WMON",
+                  "pool_created_at": "2025-02-20T11:23:16Z",
+                  "fdv_usd": "16382826.3675859",
+                  "market_cap_usd": null,
+                  "price_change_percentage": {
+                    "m5": "0.15",
+                    "m15": "0.52",
+                    "m30": "0.29",
+                    "h1": "0.63",
+                    "h6": "2.41",
+                    "h24": "1.98"
+                  },
+                  "transactions": {
+                    "m5": {
+                      "buys": 142,
+                      "sells": 23,
+                      "buyers": 136,
+                      "sellers": 23
                     },
-                    "balancer_pool_id":null,
-                    "swap_count_24h":8215,
-                    "swap_url":"https://alpha.izumi.finance/trade/swap?outputCurrency=0x6a7436775c0d0b70cff4c5365404ec37c9d9af4b",
-                    "sentiment_votes":{
-                        "total":0.0,
-                        "up_percentage":0,
-                        "down_percentage":0
+                    "m15": {
+                      "buys": 683,
+                      "sells": 102,
+                      "buyers": 632,
+                      "sellers": 97
                     },
-                    "price_percent_change":"-5.9%",
-                    "price_percent_changes":{
-                        "last_5m":"-0.41%",
-                        "last_15m":"-0.54%",
-                        "last_30m":"-0.73%",
-                        "last_1h":"-1.15%",
-                        "last_6h":"-2.35%",
-                        "last_24h":"-5.9%"
+                    "m30": {
+                      "buys": 1525,
+                      "sells": 219,
+                      "buyers": 1396,
+                      "sellers": 207
                     },
-                    "historical_data":{
-                        "last_5m":{
-                            "swaps_count":11,
-                            "buyers_count":1,
-                            "price_in_usd":"182.5310041265",
-                            "sellers_count":10,
-                            "volume_in_usd":"362.2660782419",
-                            "buy_swaps_count":1,
-                            "sell_swaps_count":10
-                        },
-                        "last_15m":{
-                            "swaps_count":23,
-                            "buyers_count":13,
-                            "price_in_usd":"182.7618519101",
-                            "sellers_count":10,
-                            "volume_in_usd":"727.4782276277",
-                            "buy_swaps_count":13,
-                            "sell_swaps_count":10
-                        },
-                        "last_30m":{
-                            "swaps_count":31,
-                            "buyers_count":15,
-                            "price_in_usd":"183.1175400712",
-                            "sellers_count":12,
-                            "volume_in_usd":"727.9833855317",
-                            "buy_swaps_count":18,
-                            "sell_swaps_count":13
-                        },
-                        "last_1h":{
-                            "swaps_count":39,
-                            "buyers_count":22,
-                            "price_in_usd":"183.8985543357",
-                            "sellers_count":12,
-                            "volume_in_usd":"768.7889156705",
-                            "buy_swaps_count":26,
-                            "sell_swaps_count":13
-                        },
-                        "last_6h":{
-                            "swaps_count":257,
-                            "buyers_count":160,
-                            "price_in_usd":"186.1624889329",
-                            "sellers_count":31,
-                            "volume_in_usd":"2018.1630831767",
-                            "buy_swaps_count":220,
-                            "sell_swaps_count":37
-                        },
-                        "last_24h":{
-                            "swaps_count":8215,
-                            "buyers_count":4051,
-                            "price_in_usd":"193.1915026651",
-                            "sellers_count":763,
-                            "volume_in_usd":"50075.0824436682",
-                            "buy_swaps_count":7242,
-                            "sell_swaps_count":973
-                        }
+                    "h1": {
+                      "buys": 3224,
+                      "sells": 457,
+                      "buyers": 2830,
+                      "sellers": 431
                     },
-                    "locked_liquidity":null,
-                    "security_indicators":[],
-                    "gt_score":34.862385321100916,
-                    "gt_score_details":{"info":0.0,"pool":31.25,"transactions":60.0,"holders":0.0,"creation":50.0},
-                    "pool_reports_count":0,
-                    "pool_created_at":"2025-02-27T07:11:12.925Z",
-                    "latest_swap_timestamp":"2025-03-12T08:59:51Z",
-                    "high_low_price_data_by_token_id":{
-                        "38379114":{
-                            "high_price_in_usd_24h":19.6155703601,
-                            "high_price_timestamp_24h":"2025-03-11T19:03:12Z",
-                            "low_price_in_usd_24h":18.1766145126,
-                            "low_price_timestamp_24h":"2025-03-12T08:59:51Z"
-                        },
-                        "38534023":{
-                            "high_price_in_usd_24h":196.9619233054,
-                            "high_price_timestamp_24h":"2025-03-11T19:03:12Z",
-                            "low_price_in_usd_24h":181.7838994589,
-                            "low_price_timestamp_24h":"2025-03-12T08:59:51Z"
-                        }
+                    "h6": {
+                      "buys": 22485,
+                      "sells": 2917,
+                      "buyers": 19351,
+                      "sellers": 2702
                     },
-                    "is_nsfw":false,
-                    "is_stale_pool":null,
-                    "is_pool_address_explorable":true
+                    "h24": {
+                      "buys": 77796,
+                      "sells": 11782,
+                      "buyers": 65320,
+                      "sellers": 10675
+                    }
+                  },
+                  "volume_usd": {
+                    "m5": "739.6638222092",
+                    "m15": "3496.6135005593",
+                    "m30": "7858.6964603576",
+                    "h1": "12176.9104960931",
+                    "h6": "74981.9754459174",
+                    "h24": "230090.703679488"
+                  },
+                  "reserve_in_usd": "1922839.6737",
+                  "locked_liquidity_percentage": null
                 },
-                "relationships":{
-                    "dex":{"data":{"id":"21916","type":"dex"}},
-                    "tokens":{"data":[{"id":"38534023","type":"token"},{"id":"38379114","type":"token"}]},
-                    "pool_metric":{"data":{"id":"4758509","type":"pool_metric"}},
-                    "pairs":{"data":[{"id":"8774160","type":"pair"}]}}
-                }
-            }"#;
-
-        let value: GeckoTerminalResponce =
-            serde_json::from_str(raw).expect("This should never happen");
-        assert_eq!(value.data.id, "171227265");
-        assert_eq!(value.data.attributes.name, "USDT / WMON 0.2%");
-        assert_eq!(
-            value.data.attributes.address,
-            "0x8552706d9a27013f20ea0f9df8e20b61e283d2d3"
-        );
-        assert_eq!(value.data.attributes.price_in_usd, 181.783899458886_f64);
-    }
-
-    #[test]
-    fn test_parsing_responce2() {
-        {
-            let raw = r#"{
-            "data": {
-              "id": "171322119",
-              "type": "pool",
-              "attributes": {
-                "address": "0x264e9b75723d75e3c607627d8e21d2c758db4c80",
-                "name": "USDC / WMON",
-                "fully_diluted_valuation": "99912242.38760373350725",
-                "base_token_id": "38379121",
-                "price_in_usd": "0.99907248024275",
-                "price_in_target_token": "0.06202568233",
-                "reserve_in_usd": "771881.4022",
-                "reserve_threshold_met": true,
-                "from_volume_in_usd": "1182787.01464575",
-                "to_volume_in_usd": "1182787.01464575",
-                "api_address": "0x264e9b75723d75e3c607627d8e21d2c758db4c80",
-                "pool_fee": null,
-                "token_weightages": null,
-                "token_reserves": {
-                  "38379114": {
-                    "reserves": "23812.4025080635",
-                    "reserves_in_usd": 385936.7889807996
+                "relationships": {
+                  "base_token": {
+                    "data": {
+                      "id": "monad-testnet_0xe0590015a873bf326bd645c3e1266d4db41c4e6b",
+                      "type": "token"
+                    }
+                  },
+                  "quote_token": {
+                    "data": {
+                      "id": "monad-testnet_0x760afe86e5de5fa0ee542fc7b7b713e1c5425701",
+                      "type": "token"
+                    }
                   },
-                  "38379121": {
-                    "reserves": "384984.918205",
-                    "reserves_in_usd": 385936.7889807977
+                  "dex": {
+                    "data": {
+                      "id": "uniswap-v2-monad-testnet",
+                      "type": "dex"
+                    }
                   }
+                }
+              },
+              {
+                "id": "monad-testnet_0x786f4aa162457ecdf8fa4657759fa3e86c9394ff",
+                "type": "pool",
+                "attributes": {
+                  "base_token_price_usd": "0.0972828246071439",
+                  "base_token_price_native_currency": "0.0100974932259467",
+                  "quote_token_price_usd": "9.66558346381163",
+                  "quote_token_price_native_currency": "1.0",
+                  "base_token_price_quote_token": "0.01009749323",
+                  "quote_token_price_base_token": "99.034480898",
+                  "address": "0x786f4aa162457ecdf8fa4657759fa3e86c9394ff",
+                  "name": "MAD / WMON",
+                  "pool_created_at": "2025-03-25T08:27:43Z",
+                  "fdv_usd": "19456564.9214288",
+                  "market_cap_usd": null,
+                  "price_change_percentage": {
+                    "m5": "0.21",
+                    "m15": "-1.21",
+                    "m30": "-1.25",
+                    "h1": "-1.04",
+                    "h6": "0.1",
+                    "h24": "2.99"
+                  },
+                  "transactions": {
+                    "m5": {
+                      "buys": 63,
+                      "sells": 36,
+                      "buyers": 62,
+                      "sellers": 36
+                    },
+                    "m15": {
+                      "buys": 412,
+                      "sells": 288,
+                      "buyers": 385,
+                      "sellers": 284
+                    },
+                    "m30": {
+                      "buys": 927,
+                      "sells": 705,
+                      "buyers": 873,
+                      "sellers": 680
+                    },
+                    "h1": {
+                      "buys": 2094,
+                      "sells": 1573,
+                      "buyers": 1921,
+                      "sellers": 1454
+                    },
+                    "h6": {
+                      "buys": 16405,
+                      "sells": 8271,
+                      "buyers": 14991,
+                      "sellers": 7575
+                    },
+                    "h24": {
+                      "buys": 52172,
+                      "sells": 25300,
+                      "buyers": 43184,
+                      "sellers": 20155
+                    }
+                  },
+                  "volume_usd": {
+                    "m5": "1422.4554366557",
+                    "m15": "11496.5277953363",
+                    "m30": "18617.0585445526",
+                    "h1": "33859.884755605",
+                    "h6": "188757.334947648",
+                    "h24": "671102.691301966"
+                  },
+                  "reserve_in_usd": "677771.1159",
+                  "locked_liquidity_percentage": null
                 },
-                "token_value_data": {
-                  "38379114": {
-                    "fdv_in_usd": 1644321102.7761497,
-                    "market_cap_in_usd": null,
-                    "market_cap_to_holders_ratio": null
+                "relationships": {
+                  "base_token": {
+                    "data": {
+                      "id": "monad-testnet_0xc8527e96c3cb9522f6e35e95c0a28feab8144f15",
+                      "type": "token"
+                    }
+                  },
+                  "quote_token": {
+                    "data": {
+                      "id": "monad-testnet_0x760afe86e5de5fa0ee542fc7b7b713e1c5425701",
+                      "type": "token"
+                    }
                   },
-                  "38379121": {
-                    "fdv_in_usd": 100252259.55218814,
-                    "market_cap_in_usd": null,
-                    "market_cap_to_holders_ratio": null
+                  "dex": {
+                    "data": {
+                      "id": "madness-finance",
+                      "type": "dex"
+                    }
                   }
-                },
-                "balancer_pool_id": null,
-                "swap_count_24h": 132038,
-                "swap_url": "https://swap.bean.exchange/swap?outputCurrency=0xf817257fed379853cde0fa4f97ab987181b1e5ea",
-                "sentiment_votes": {
-                  "total": 0.0,
-                  "up_percentage": 0,
-                  "down_percentage": 0
-                },
-                "price_percent_change": "+0.57%",
-                "price_percent_changes": {
-                  "last_5m": "-0.1%",
-                  "last_15m": "-0.48%",
-                  "last_30m": "+0.36%",
-                  "last_1h": "-0.04%",
-                  "last_6h": "-0.08%",
-                  "last_24h": "+0.6%"
-                },
-                "historical_data": {
-                  "last_5m": {
-                    "swaps_count": 593,
-                    "buyers_count": 356,
-                    "price_in_usd": "1.0065622534",
-                    "sellers_count": 149,
-                    "volume_in_usd": "6124.5596226486",
-                    "buy_swaps_count": 406,
-                    "sell_swaps_count": 187
+                }
+              },
+              {
+                "id": "monad-testnet_0xf2afc5aa9965cdb2d4be94823c98411291b61297",
+                "type": "pool",
+                "attributes": {
+                  "base_token_price_usd": "2.04359324869297",
+                  "base_token_price_native_currency": "0.210846464198185",
+                  "quote_token_price_usd": "9.66558346381163",
+                  "quote_token_price_native_currency": "1.0",
+                  "base_token_price_quote_token": "0.2108464642",
+                  "quote_token_price_base_token": "4.742787619",
+                  "address": "0xf2afc5aa9965cdb2d4be94823c98411291b61297",
+                  "name": "BEAN / WMON",
+                  "pool_created_at": "2025-03-03T09:24:13Z",
+                  "fdv_usd": "20435932.4869297",
+                  "market_cap_usd": null,
+                  "price_change_percentage": {
+                    "m5": "-0.56",
+                    "m15": "-0.56",
+                    "m30": "-0.09",
+                    "h1": "-0.51",
+                    "h6": "-1.84",
+                    "h24": "3.93"
                   },
-                  "last_15m": {
-                    "swaps_count": 1694,
-                    "buyers_count": 968,
-                    "price_in_usd": "1.0103727702",
-                    "sellers_count": 429,
-                    "volume_in_usd": "18653.5217858644",
-                    "buy_swaps_count": 1133,
-                    "sell_swaps_count": 561
+                  "transactions": {
+                    "m5": {
+                      "buys": 65,
+                      "sells": 36,
+                      "buyers": 57,
+                      "sellers": 35
+                    },
+                    "m15": {
+                      "buys": 378,
+                      "sells": 275,
+                      "buyers": 329,
+                      "sellers": 233
+                    },
+                    "m30": {
+                      "buys": 805,
+                      "sells": 603,
+                      "buyers": 709,
+                      "sellers": 499
+                    },
+                    "h1": {
+                      "buys": 1719,
+                      "sells": 1273,
+                      "buyers": 1470,
+                      "sellers": 1051
+                    },
+                    "h6": {
+                      "buys": 11277,
+                      "sells": 8585,
+                      "buyers": 9564,
+                      "sellers": 7013
+                    },
+                    "h24": {
+                      "buys": 39639,
+                      "sells": 31354,
+                      "buyers": 32381,
+                      "sellers": 23701
+                    }
                   },
-                  "last_30m": {
-                    "swaps_count": 3382,
-                    "buyers_count": 1838,
-                    "price_in_usd": "1.0019221173",
-                    "sellers_count": 849,
-                    "volume_in_usd": "31374.4927020119",
-                    "buy_swaps_count": 2248,
-                    "sell_swaps_count": 1134
+                  "volume_usd": {
+                    "m5": "469.1485180185",
+                    "m15": "3035.4263622067",
+                    "m30": "6601.7638933551",
+                    "h1": "18009.5587594932",
+                    "h6": "120533.38678189",
+                    "h24": "418258.18936751"
                   },
-                  "last_1h": {
-                    "swaps_count": 6551,
-                    "buyers_count": 3488,
-                    "price_in_usd": "1.005909513",
-                    "sellers_count": 1651,
-                    "volume_in_usd": "65201.6371308379",
-                    "buy_swaps_count": 4348,
-                    "sell_swaps_count": 2203
+                  "reserve_in_usd": "651740.0172",
+                  "locked_liquidity_percentage": null
+                },
+                "relationships": {
+                  "base_token": {
+                    "data": {
+                      "id": "monad-testnet_0x268e4e24e0051ec27b3d27a95977e71ce6875a05",
+                      "type": "token"
+                    }
                   },
-                  "last_6h": {
-                    "swaps_count": 37577,
-                    "buyers_count": 18981,
-                    "price_in_usd": "1.0062752729",
-                    "sellers_count": 8834,
-                    "volume_in_usd": "359464.647861938",
-                    "buy_swaps_count": 25236,
-                    "sell_swaps_count": 12341
+                  "quote_token": {
+                    "data": {
+                      "id": "monad-testnet_0x760afe86e5de5fa0ee542fc7b7b713e1c5425701",
+                      "type": "token"
+                    }
                   },
-                  "last_24h": {
-                    "swaps_count": 132038,
-                    "buyers_count": 58038,
-                    "price_in_usd": "0.9995505107",
-                    "sellers_count": 29131,
-                    "volume_in_usd": "1182787.01464575",
-                    "buy_swaps_count": 85971,
-                    "sell_swaps_count": 46067
+                  "dex": {
+                    "data": {
+                      "id": "bean-exchange",
+                      "type": "dex"
+                    }
                   }
+                }
+              },
+              {
+                "id": "monad-testnet_0xf22d36b6bee8a7fd51def4e3badf35a8733b284f",
+                "type": "pool",
+                "attributes": {
+                  "base_token_price_usd": "0.998048030025504",
+                  "base_token_price_native_currency": "0.103255170822637",
+                  "quote_token_price_usd": "9.66558346381163",
+                  "quote_token_price_native_currency": "1.0",
+                  "base_token_price_quote_token": "0.1032551708",
+                  "quote_token_price_base_token": "9.684745006",
+                  "address": "0xf22d36b6bee8a7fd51def4e3badf35a8733b284f",
+                  "name": "USDC / WMON 0.2%",
+                  "pool_created_at": "2025-02-27T07:11:16Z",
+                  "fdv_usd": "99809791.5916197",
+                  "market_cap_usd": null,
+                  "price_change_percentage": {
+                    "m5": "0",
+                    "m15": "0.2",
+                    "m30": "-0.15",
+                    "h1": "0.12",
+                    "h6": "-0.06",
+                    "h24": "-0.83"
+                  },
+                  "transactions": {
+                    "m5": {
+                      "buys": 11,
+                      "sells": 0,
+                      "buyers": 11,
+                      "sellers": 0
+                    },
+                    "m15": {
+                      "buys": 86,
+                      "sells": 0,
+                      "buyers": 86,
+                      "sellers": 0
+                    },
+                    "m30": {
+                      "buys": 187,
+                      "sells": 4,
+                      "buyers": 186,
+                      "sellers": 4
+                    },
+                    "h1": {
+                      "buys": 425,
+                      "sells": 23,
+                      "buyers": 421,
+                      "sellers": 23
+                    },
+                    "h6": {
+                      "buys": 2217,
+                      "sells": 92,
+                      "buyers": 2176,
+                      "sellers": 87
+                    },
+                    "h24": {
+                      "buys": 5099,
+                      "sells": 388,
+                      "buyers": 4981,
+                      "sellers": 348
+                    }
+                  },
+                  "volume_usd": {
+                    "m5": "0.1637132055",
+                    "m15": "96.8330105108",
+                    "m30": "769.1949284789",
+                    "h1": "1636.7935371706",
+                    "h6": "18930.8550704817",
+                    "h24": "69105.7469459649"
+                  },
+                  "reserve_in_usd": "944741.6508",
+                  "locked_liquidity_percentage": null
                 },
-                "security_indicators": [],
-                "gt_score": 42.201834862385326,
-                "gt_score_details": {
-                  "info": 0.0,
-                  "pool": 31.25,
-                  "transactions": 100.0,
-                  "holders": 0.0,
-                  "creation": 50.0
-                },
-                "pool_reports_count": 0,
-                "pool_created_at": "2025-03-03T09:23:55.319Z",
-                "latest_swap_timestamp": "2025-03-17T10:45:23Z",
-                "high_low_price_data_by_token_id": {
-                  "38379114": {
-                    "high_price_in_usd_24h": 17.1288829538,
-                    "high_price_timestamp_24h": "2025-03-17T09:00:51Z",
-                    "low_price_in_usd_24h": 16.0266401781,
-                    "low_price_timestamp_24h": "2025-03-17T08:37:39Z"
+                "relationships": {
+                  "base_token": {
+                    "data": {
+                      "id": "monad-testnet_0xf817257fed379853cde0fa4f97ab987181b1e5ea",
+                      "type": "token"
+                    }
+                  },
+                  "quote_token": {
+                    "data": {
+                      "id": "monad-testnet_0x760afe86e5de5fa0ee542fc7b7b713e1c5425701",
+                      "type": "token"
+                    }
                   },
-                  "38379121": {
-                    "high_price_in_usd_24h": 1.0518595445,
-                    "high_price_timestamp_24h": "2025-03-17T09:16:25Z",
-                    "low_price_in_usd_24h": 0.9787653682,
-                    "low_price_timestamp_24h": "2025-03-16T21:11:35Z"
+                  "dex": {
+                    "data": {
+                      "id": "iziswap-monad-testnet",
+                      "type": "dex"
+                    }
                   }
-                },
-                "is_nsfw": false,
-                "is_stale_pool": null,
-                "is_pool_address_explorable": true
+                }
               },
-              "relationships": {
-                "dex": {
-                  "data": {
-                    "id": "22120",
-                    "type": "dex"
-                  }
+              {
+                "id": "monad-testnet_0xe8a806ae6ecb1f02063e21c6f0579b145399ee5f",
+                "type": "pool",
+                "attributes": {
+                  "base_token_price_usd": "0.000272421298758802",
+                  "base_token_price_native_currency": "0.000028251230201563",
+                  "quote_token_price_usd": "9.66558346381163",
+                  "quote_token_price_native_currency": "1.0",
+                  "base_token_price_quote_token": "0.0000282512302",
+                  "quote_token_price_base_token": "35396.688670381",
+                  "address": "0xe8a806ae6ecb1f02063e21c6f0579b145399ee5f",
+                  "name": "JAI / WMON",
+                  "pool_created_at": "2025-03-03T09:24:01Z",
+                  "fdv_usd": "2724212.98758802",
+                  "market_cap_usd": null,
+                  "price_change_percentage": {
+                    "m5": "-0.61",
+                    "m15": "0.8",
+                    "m30": "0.14",
+                    "h1": "-0.33",
+                    "h6": "4.57",
+                    "h24": "6.35"
+                  },
+                  "transactions": {
+                    "m5": {
+                      "buys": 68,
+                      "sells": 37,
+                      "buyers": 66,
+                      "sellers": 35
+                    },
+                    "m15": {
+                      "buys": 385,
+                      "sells": 241,
+                      "buyers": 333,
+                      "sellers": 211
+                    },
+                    "m30": {
+                      "buys": 799,
+                      "sells": 508,
+                      "buyers": 684,
+                      "sellers": 438
+                    },
+                    "h1": {
+                      "buys": 1635,
+                      "sells": 1079,
+                      "buyers": 1353,
+                      "sellers": 899
+                    },
+                    "h6": {
+                      "buys": 10101,
+                      "sells": 6549,
+                      "buyers": 8400,
+                      "sellers": 5341
+                    },
+                    "h24": {
+                      "buys": 32791,
+                      "sells": 22685,
+                      "buyers": 26648,
+                      "sellers": 16887
+                    }
+                  },
+                  "volume_usd": {
+                    "m5": "513.6051349287",
+                    "m15": "1889.3327488214",
+                    "m30": "3778.2071474251",
+                    "h1": "9654.7724745484",
+                    "h6": "69628.8997032741",
+                    "h24": "190282.75040509"
+                  },
+                  "reserve_in_usd": "298605.8652",
+                  "locked_liquidity_percentage": null
                 },
-                "tokens": {
-                  "data": [
-                    {
-                      "id": "38379114",
+                "relationships": {
+                  "base_token": {
+                    "data": {
+                      "id": "monad-testnet_0xcc5b42f9d6144dfdfb6fb3987a2a916af902f5f8",
                       "type": "token"
-                    },
-                    {
-                      "id": "38379121",
+                    }
+                  },
+                  "quote_token": {
+                    "data": {
+                      "id": "monad-testnet_0x760afe86e5de5fa0ee542fc7b7b713e1c5425701",
                       "type": "token"
                     }
-                  ]
-                },
-                "pool_metric": {
-                  "data": {
-                    "id": "4818589",
-                    "type": "pool_metric"
+                  },
+                  "dex": {
+                    "data": {
+                      "id": "bean-exchange",
+                      "type": "dex"
+                    }
                   }
+                }
+              }
+            ]
+          }"#;
+        let value: GeckoTerminalMultipleResponce =
+            serde_json::from_str(raw).expect("This should never happen");
+        assert_eq!(value.data.len(), 5);
+        assert_eq!(
+            value.data[0].attributes.volume_usd.h24,
+            230090.703679488_f64
+        );
+        assert_eq!(value.data[0].attributes.name, "CHOG / WMON");
+        assert_eq!(
+            value.data[0].attributes.quote_token_price_usd,
+            9.66558346381163_f64
+        );
+
+        assert_eq!(value.data[1].attributes.name, "MAD / WMON");
+        assert_eq!(
+            value.data[1].attributes.quote_token_price_usd,
+            9.66558346381163_f64
+        );
+        assert_eq!(
+            value.data[1].attributes.volume_usd.h24,
+            671102.691301966_f64
+        );
+
+        assert_eq!(value.data[2].attributes.name, "BEAN / WMON");
+        assert_eq!(
+            value.data[2].attributes.quote_token_price_usd,
+            9.66558346381163_f64
+        );
+        assert_eq!(value.data[2].attributes.volume_usd.h24, 418258.18936751_f64);
+
+        assert_eq!(value.data[3].attributes.name, "USDC / WMON 0.2%");
+        assert_eq!(
+            value.data[3].attributes.quote_token_price_usd,
+            9.66558346381163_f64
+        );
+        assert_eq!(
+            value.data[3].attributes.volume_usd.h24,
+            69105.7469459649_f64
+        );
+
+        assert_eq!(value.data[4].attributes.name, "JAI / WMON");
+        assert_eq!(
+            value.data[4].attributes.quote_token_price_usd,
+            9.66558346381163_f64
+        );
+        assert_eq!(value.data[4].attributes.volume_usd.h24, 190282.75040509_f64);
+    }
+    #[test]
+    fn test_parsing_responce2() {
+        let raw = r#"{
+        "data": [
+          {
+            "id": "base_0xd3ee0a3b349237d68517df30bfb66be971f46ad9",
+            "type": "pool",
+            "attributes": {
+              "base_token_price_usd": "0.997490689159406",
+              "base_token_price_native_currency": "0.000632854458009392",
+              "quote_token_price_usd": "0.998787044324444",
+              "quote_token_price_native_currency": "0.00063405388659788",
+              "base_token_price_quote_token": "0.9981083176",
+              "quote_token_price_base_token": "1.0018952677",
+              "address": "0xd3ee0a3b349237d68517df30bfb66be971f46ad9",
+              "name": "USR / USDC",
+              "pool_created_at": "2024-12-02T22:34:37Z",
+              "fdv_usd": "144973204.632112",
+              "market_cap_usd": null,
+              "price_change_percentage": {
+                "m5": "0",
+                "m15": "0.06",
+                "m30": "-0.09",
+                "h1": "-0.05",
+                "h6": "-0.22",
+                "h24": "0.47"
+              },
+              "transactions": {
+                "m5": {
+                  "buys": 0,
+                  "sells": 0,
+                  "buyers": 0,
+                  "sellers": 0
                 },
-                "pairs": {
-                  "data": [
-                    {
-                      "id": "8883031",
-                      "type": "pair"
-                    }
-                  ]
+                "m15": {
+                  "buys": 2,
+                  "sells": 0,
+                  "buyers": 2,
+                  "sellers": 0
+                },
+                "m30": {
+                  "buys": 3,
+                  "sells": 3,
+                  "buyers": 3,
+                  "sellers": 2
+                },
+                "h1": {
+                  "buys": 20,
+                  "sells": 6,
+                  "buyers": 8,
+                  "sellers": 5
+                },
+                "h6": {
+                  "buys": 23,
+                  "sells": 24,
+                  "buyers": 11,
+                  "sellers": 21
+                },
+                "h24": {
+                  "buys": 49,
+                  "sells": 85,
+                  "buyers": 31,
+                  "sellers": 68
+                }
+              },
+              "volume_usd": {
+                "m5": "0.0",
+                "m15": "5341.1193886335",
+                "m30": "6237.4529742006",
+                "h1": "123860.982100642",
+                "h6": "148433.641050373",
+                "h24": "210526.004942701"
+              },
+              "reserve_in_usd": "3392810.9864",
+              "locked_liquidity_percentage": null
+            },
+            "relationships": {
+              "base_token": {
+                "data": {
+                  "id": "base_0x35e5db674d8e93a03d814fa0ada70731efe8a4b9",
+                  "type": "token"
+                }
+              },
+              "quote_token": {
+                "data": {
+                  "id": "base_0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
+                  "type": "token"
+                }
+              },
+              "dex": {
+                "data": {
+                  "id": "aerodrome-base",
+                  "type": "dex"
                 }
               }
             }
-          }"#;
-            let value: GeckoTerminalResponce =
-                serde_json::from_str(raw).expect("This should never happen");
-            assert_eq!(value.reserve_price_in_usd(), 16.107400075460806_f64);
-        }
+          },
+          {
+            "id": "base_0xb924561a57fc60041414b8471cbc99d3497097fa",
+            "type": "pool",
+            "attributes": {
+              "base_token_price_usd": "1.00244546610649",
+              "base_token_price_native_currency": "0.000638561305925082330775418713143738184617765790084025952771880425794618593714181536695755847559027949859320808534079832978953784783334219422790840561637754665609314017111333100834555600394379500334700225792233833307826491619428603601518251226221771170345560754060429714593718891488560444271960565278243646885132330496944089456438767015705478136268576948153686135601909269118815897086005710310649101811160895904113135274537560227584716357122710243795066046366788052442814641284853729799888505713662838340479402208940109758309452148946805383687314228509488124102463834324264137269323032787452495160606133842808898755332890688321848151292996462763295319523124748349232655583936087226228104619438905190422786496263882345028426668946587373679703487275720987029142651054975480173353188778139135049654203712942804897944218259781279458236563921704688709310450503747166546250447295927230500246652158358450427881421559119663501199909172607038456707096317859849275704370800883810029620403025179519662729299126892634278172820099309297972780099836737795831717750829300450535238318410265849907179244168181679746200812635117434128434429820397285887422259043686669695239388373012941672986104443438507295614123153501545645570688364078675404453321350641808549256186071713563396529304912017259298135123592042847764725057568438757559097451650715596182158027100346370749640621569391490382004559030044528565868524819618313272402396575092965654",
+              "quote_token_price_usd": "1.00802432126983",
+              "quote_token_price_native_currency": "0.000642115056387444",
+              "base_token_price_quote_token": "0.994465555",
+              "quote_token_price_base_token": "1.0055652455",
+              "address": "0xb924561a57fc60041414b8471cbc99d3497097fa",
+              "name": "USR / GYD 0.01%",
+              "pool_created_at": "2025-02-24T01:22:27Z",
+              "fdv_usd": "145693321.521485",
+              "market_cap_usd": null,
+              "price_change_percentage": {
+                "m5": "0",
+                "m15": "0",
+                "m30": "0",
+                "h1": "-0.55",
+                "h6": "0.33",
+                "h24": "-0.12"
+              },
+              "transactions": {
+                "m5": {
+                  "buys": 0,
+                  "sells": 0,
+                  "buyers": 0,
+                  "sellers": 0
+                },
+                "m15": {
+                  "buys": 0,
+                  "sells": 0,
+                  "buyers": 0,
+                  "sellers": 0
+                },
+                "m30": {
+                  "buys": 0,
+                  "sells": 0,
+                  "buyers": 0,
+                  "sellers": 0
+                },
+                "h1": {
+                  "buys": 0,
+                  "sells": 11,
+                  "buyers": 0,
+                  "sellers": 5
+                },
+                "h6": {
+                  "buys": 0,
+                  "sells": 29,
+                  "buyers": 0,
+                  "sellers": 8
+                },
+                "h24": {
+                  "buys": 3,
+                  "sells": 53,
+                  "buyers": 3,
+                  "sellers": 10
+                }
+              },
+              "volume_usd": {
+                "m5": "0.0",
+                "m15": "0.0",
+                "m30": "0.0",
+                "h1": "52587.2311650526",
+                "h6": "80711.4249267678",
+                "h24": "112969.273817945"
+              },
+              "reserve_in_usd": "150263.1042",
+              "locked_liquidity_percentage": null
+            },
+            "relationships": {
+              "base_token": {
+                "data": {
+                  "id": "base_0x35e5db674d8e93a03d814fa0ada70731efe8a4b9",
+                  "type": "token"
+                }
+              },
+              "quote_token": {
+                "data": {
+                  "id": "base_0xca5d8f8a8d49439357d3cf46ca2e720702f132b8",
+                  "type": "token"
+                }
+              },
+              "dex": {
+                "data": {
+                  "id": "balancer-v2-base",
+                  "type": "dex"
+                }
+              }
+            }
+          },
+          {
+            "id": "base_0x97c9750305a39e06002edd851f3d37a862ac7060",
+            "type": "pool",
+            "attributes": {
+              "base_token_price_usd": "1.00709295457369",
+              "base_token_price_native_currency": "0.0006328541735874420458786112741188022282694091137612199079829207559642391225928911146062088086661629463406547926380158977335562593485335063864482938660201715656129851686969550476096314663313695317509472711620475290220802945059294613828426903633693166835521913121911140130370701201916776913866153519435899463952728309037017697666219113171038688955735031697851705354754644066561104755718493822982678403916552097850705647547626902615471106603232040378312443527407868354985818230611191789513341850530077949900534339777352415309737172518880680185913659766815313543095034905744485097159312933150099473502417145821834761485203552323034154048395721499356683243368492412348369197009895308239277155526170550278430876991117359942991376053909890389239666257287310185426046738778551022586835849225123667050602808889776978609824100773686123979531412251653828651237911305715677690675728540635363381534285214197004863394129678113474609060558471296178960465504871736010528492721294381431297040718757791927675807612856384369052902180422540226848726308608950566728664948540258675097114668435155011792882744178294708235064227672227445176608987602501035164237256380182689617376132813383165970380699702973093464324364175292389840339875548100180529102948896239207126195728016666295884845962619560039846815822902084676737088064405367261144098587151888488882226223975995916265182183934984238491476460072198950168123821282951808961168000486170412504",
+              "quote_token_price_usd": "1.00863181431767",
+              "quote_token_price_native_currency": "0.000641741679010549",
+              "base_token_price_quote_token": "0.9861509612",
+              "quote_token_price_base_token": "1.0140435282",
+              "address": "0x97c9750305a39e06002edd851f3d37a862ac7060",
+              "name": "USR / USDC 0.01%",
+              "pool_created_at": "2024-12-25T08:51:13Z",
+              "fdv_usd": "146368777.747697",
+              "market_cap_usd": null,
+              "price_change_percentage": {
+                "m5": "0",
+                "m15": "0.84",
+                "m30": "0.88",
+                "h1": "0.15",
+                "h6": "0.67",
+                "h24": "-0.08"
+              },
+              "transactions": {
+                "m5": {
+                  "buys": 0,
+                  "sells": 1,
+                  "buyers": 0,
+                  "sellers": 1
+                },
+                "m15": {
+                  "buys": 4,
+                  "sells": 4,
+                  "buyers": 4,
+                  "sellers": 4
+                },
+                "m30": {
+                  "buys": 5,
+                  "sells": 4,
+                  "buyers": 4,
+                  "sellers": 4
+                },
+                "h1": {
+                  "buys": 9,
+                  "sells": 10,
+                  "buyers": 8,
+                  "sellers": 10
+                },
+                "h6": {
+                  "buys": 41,
+                  "sells": 52,
+                  "buyers": 35,
+                  "sellers": 39
+                },
+                "h24": {
+                  "buys": 117,
+                  "sells": 207,
+                  "buyers": 87,
+                  "sellers": 140
+                }
+              },
+              "volume_usd": {
+                "m5": "7.0362125108",
+                "m15": "16377.1016416017",
+                "m30": "16381.18656097",
+                "h1": "266095.8935227",
+                "h6": "616975.60880721",
+                "h24": "1012903.95537022"
+              },
+              "reserve_in_usd": "505703.2809",
+              "locked_liquidity_percentage": null
+            },
+            "relationships": {
+              "base_token": {
+                "data": {
+                  "id": "base_0x35e5db674d8e93a03d814fa0ada70731efe8a4b9",
+                  "type": "token"
+                }
+              },
+              "quote_token": {
+                "data": {
+                  "id": "base_0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
+                  "type": "token"
+                }
+              },
+              "dex": {
+                "data": {
+                  "id": "pancakeswap-v3-base",
+                  "type": "dex"
+                }
+              }
+            }
+          },
+          {
+            "id": "base_0xcf88b8bf7ccce2d836878e538197eb20fc673bce",
+            "type": "pool",
+            "attributes": {
+              "base_token_price_usd": "0.987063334395549",
+              "base_token_price_native_currency": "0.000625664661078533300867880765991673013377843703361258141558068975160472331702149448974391333802854899002661080058759071442173599855258793265320836223822492610173135843654973101015671832940709410927293073886355986629957063441005522165866484240419290894156039466550356193471474936055193153825480552400823708878259081259158890603811179829764085747022125617253192433411805538632540004855168574911826160798185812229142293551958493375104099615327050334137218053498443124908515097689552508255595690451784893617119810552324030145223015997144886245174019196570640561091365659590229231156560705464875157538561806871547221531125310924841453033670000932262349961092656097005562753737444958309247423593833774012607397101519120073279021117058934601195153109401034223309750507004507139670643551556963626701363877365042715987734241736648269386843926312560467643547168196384951265605338743929763733148529359848012028472169781028699659933515457259958690791042415269972889841242938894875485955062235391065011362689700702042397421383298508382666208213626254672763478255139686521168605986423137767634262778431692107398680016646384617755287386431613324142549791470012490806901953525350060532867984726887715398316127338318416401969418135489018313127204052518300577921297841988779835882477649120344148828784642184238363694312883214650958589931118016056946456753839607995033789191357920616754059502737259130148077698882142590933868916538950105933433082996633582230763556311475922239044594265040611923798253025512482449397314355836671537842465261660070794938698224376056267661184378595157513391256523483817018630503832462984958100980600537150491046154667877818030987440324516741420451714315264119950452605979064928697050478146292752322925651991247826781953340839109954703351516142236797697494953329299774792019792950035658553155296959564348119016431608549095539108243090428200891314413235813508274073181827127028670616204063377782482988422755535122979943129261900246091395968651836493534334577754227775265980070798827767177347705731043291505509903805365293963921910132477073116320318452517165099134923505085214400490178084461128328357383698946582789606621771432134659974171904944894452052231132402108878405451875784389012155182583275084679575328897530920862119184260987016188211200238730393615483788745593339725989897437037806313042089800085429145792208025139586101991277414293479499496902592105667254427854221538094981598380736419589988744728052957800925662901488835925834615596389891606363550555970398945038766065202582885057231786543504673115768823197517842704858192685017717279902239877990125188736847637467489586546097654646492668595830088315995302618725039884896038139988298114364565111314248891413680253118200638920707529453103670325679901310642300359970109220263417547044783093994611812817699832486238371281097999273385045268224874448357913049131661664834105064723171522200631978088539473814364204616590078357440468962342720362734266818327805824074355837740534551007740765266918503114005878517393050290137121778258060608219580831241528933517919872028989791179545503805865027258952901436488057181684731478816337227629959721326031406631103902027463943118844386783382555273940399997058014138502816630500425568312725731946803397308332029789458715441105023769739803235780239466501148772211156321619697240175976651198354370395516414530277544951600803860201506208646649412567211227158470227829425411361095820886047075430858962111253410205324829346843257252094098220946320211937358701307547404197560685894543255292007961299470003396669928420341592192265296323755192226302243652976483704314440588390286029353882735375279506604434430757332366600536152720514921711022820382907215241567291788864031195680500148315823581307703893358945186833015710108063798981707087284254693634892802445918592940672853680631417275307134861471514136001906645035445384334966885189174894209291860814751277149046109289571066769966103023019538008607203331720336524772778797208",
+              "quote_token_price_usd": "1570.35",
+              "quote_token_price_native_currency": "1.0",
+              "base_token_price_quote_token": "0.0006256646611",
+              "quote_token_price_base_token": "1598.3002752244",
+              "address": "0xcf88b8bf7ccce2d836878e538197eb20fc673bce",
+              "name": "USDz / WETH 0.04%",
+              "pool_created_at": "2024-07-18T23:50:02Z",
+              "fdv_usd": "115609034.747141",
+              "market_cap_usd": "124306472.308307",
+              "price_change_percentage": {
+                "m5": "0.1",
+                "m15": "0.59",
+                "m30": "0.78",
+                "h1": "0.73",
+                "h6": "0.62",
+                "h24": "2.09"
+              },
+              "transactions": {
+                "m5": {
+                  "buys": 4,
+                  "sells": 1,
+                  "buyers": 4,
+                  "sellers": 1
+                },
+                "m15": {
+                  "buys": 12,
+                  "sells": 3,
+                  "buyers": 11,
+                  "sellers": 3
+                },
+                "m30": {
+                  "buys": 25,
+                  "sells": 16,
+                  "buyers": 16,
+                  "sellers": 12
+                },
+                "h1": {
+                  "buys": 55,
+                  "sells": 43,
+                  "buyers": 35,
+                  "sellers": 24
+                },
+                "h6": {
+                  "buys": 162,
+                  "sells": 159,
+                  "buyers": 62,
+                  "sellers": 42
+                },
+                "h24": {
+                  "buys": 658,
+                  "sells": 683,
+                  "buyers": 172,
+                  "sellers": 162
+                }
+              },
+              "volume_usd": {
+                "m5": "22.914503934",
+                "m15": "75.9913029647",
+                "m30": "205.8115131572",
+                "h1": "546.5694719221",
+                "h6": "1515.7560972564",
+                "h24": "7710.7790743691"
+              },
+              "reserve_in_usd": "16273.0891",
+              "locked_liquidity_percentage": null
+            },
+            "relationships": {
+              "base_token": {
+                "data": {
+                  "id": "base_0x04d5ddf5f3a8939889f11e97f8c4bb48317f1938",
+                  "type": "token"
+                }
+              },
+              "quote_token": {
+                "data": {
+                  "id": "base_0x4200000000000000000000000000000000000006",
+                  "type": "token"
+                }
+              },
+              "dex": {
+                "data": {
+                  "id": "aerodrome-slipstream",
+                  "type": "dex"
+                }
+              }
+            }
+          },
+          {
+            "id": "base_0x6d0b9c9e92a3de30081563c3657b5258b3ffa38b",
+            "type": "pool",
+            "attributes": {
+              "base_token_price_usd": "0.977116821708074",
+              "base_token_price_native_currency": "0.00063111259894421",
+              "quote_token_price_usd": "0.998757565692604",
+              "quote_token_price_native_currency": "0.000637796587178776",
+              "base_token_price_quote_token": "0.9895201881",
+              "quote_token_price_base_token": "1.0105908015",
+              "address": "0x6d0b9c9e92a3de30081563c3657b5258b3ffa38b",
+              "name": "USDz / USDC",
+              "pool_created_at": "2024-05-22T02:00:04Z",
+              "fdv_usd": "114444057.089853",
+              "market_cap_usd": "124306472.308307",
+              "price_change_percentage": {
+                "m5": "0",
+                "m15": "0",
+                "m30": "0",
+                "h1": "-1.52",
+                "h6": "-0.39",
+                "h24": "-0.2"
+              },
+              "transactions": {
+                "m5": {
+                  "buys": 0,
+                  "sells": 0,
+                  "buyers": 0,
+                  "sellers": 0
+                },
+                "m15": {
+                  "buys": 0,
+                  "sells": 0,
+                  "buyers": 0,
+                  "sellers": 0
+                },
+                "m30": {
+                  "buys": 0,
+                  "sells": 0,
+                  "buyers": 0,
+                  "sellers": 0
+                },
+                "h1": {
+                  "buys": 1,
+                  "sells": 2,
+                  "buyers": 1,
+                  "sellers": 2
+                },
+                "h6": {
+                  "buys": 5,
+                  "sells": 10,
+                  "buyers": 4,
+                  "sellers": 8
+                },
+                "h24": {
+                  "buys": 23,
+                  "sells": 55,
+                  "buyers": 5,
+                  "sellers": 31
+                }
+              },
+              "volume_usd": {
+                "m5": "0.0",
+                "m15": "0.0",
+                "m30": "0.0",
+                "h1": "276.6643908159",
+                "h6": "2527.6780576674",
+                "h24": "27258.7391844075"
+              },
+              "reserve_in_usd": "340057.2872",
+              "locked_liquidity_percentage": null
+            },
+            "relationships": {
+              "base_token": {
+                "data": {
+                  "id": "base_0x04d5ddf5f3a8939889f11e97f8c4bb48317f1938",
+                  "type": "token"
+                }
+              },
+              "quote_token": {
+                "data": {
+                  "id": "base_0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
+                  "type": "token"
+                }
+              },
+              "dex": {
+                "data": {
+                  "id": "aerodrome-base",
+                  "type": "dex"
+                }
+              }
+            }
+          }
+        ]
+      }"#;
+
+        let value: GeckoTerminalMultipleResponce =
+            serde_json::from_str(raw).expect("This should never happen");
+        assert_eq!(value.data.len(), 5);
     }
 }
diff --git a/apps/sequencer/src/http_handlers/admin.rs b/apps/sequencer/src/http_handlers/admin.rs
index a8371c9733..2f3da53ac5 100644
--- a/apps/sequencer/src/http_handlers/admin.rs
+++ b/apps/sequencer/src/http_handlers/admin.rs
@@ -536,7 +536,7 @@ pub async fn get_oracle_scripts(
                 name: None,
                 description: None,
                 oracle_script_wasm: "gecko_terminal_oracle.wasm".to_string(),
-                allowed_outbound_hosts: vec!["https://app.geckoterminal.com/".to_string()],
+                allowed_outbound_hosts: vec!["https://api.geckoterminal.com".to_string()],
                 capabilities: HashSet::new(),
             },
             OracleScript {
diff --git a/config/feeds_config_v2.json b/config/feeds_config_v2.json
index a10ca00f31..1c186e51cb 100644
--- a/config/feeds_config_v2.json
+++ b/config/feeds_config_v2.json
@@ -53419,52 +53419,62 @@
           {
             "network": "monad-testnet",
             "pool": "0x264e9b75723d75e3c607627d8e21d2c758db4c80",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           },
           {
             "network": "monad-testnet",
             "pool": "0x8552706d9a27013f20ea0f9df8e20b61e283d2d3",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           },
           {
             "network": "monad-testnet",
             "pool": "0x5323821de342c56b80c99fbc7cd725f2da8eb87b",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           },
           {
             "network": "monad-testnet",
             "pool": "0x6e4b7be5ef7f8950c76baa0bd90125bc9b33c8db",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           },
           {
             "network": "monad-testnet",
             "pool": "0x212fde77a42d55f980d0a0304e7eebe1e999c60f",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           },
           {
             "network": "monad-testnet",
             "pool": "0xc0ce32eee0eb8bf24fa2b00923a78abc5002f91e",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           },
           {
             "network": "monad-testnet",
             "pool": "0x786f4aa162457ecdf8fa4657759fa3e86c9394ff",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           },
           {
             "network": "monad-testnet",
             "pool": "0xf2afc5aa9965cdb2d4be94823c98411291b61297",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           },
           {
             "network": "monad-testnet",
             "pool": "0xf22d36b6bee8a7fd51def4e3badf35a8733b284f",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           },
           {
             "network": "monad-testnet",
             "pool": "0xe8a806ae6ecb1f02063e21c6f0579b145399ee5f",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           }
         ]
       }
@@ -53499,52 +53509,62 @@
           {
             "network": "base",
             "pool": "0xcf88b8bf7ccce2d836878e538197eb20fc673bce",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":10000.0
           },
           {
             "network": "base",
             "pool": "0x6d0b9c9e92a3de30081563c3657b5258b3ffa38b",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":10000.0
           },
           {
             "network": "base",
             "pool": "0xebf0e4da26a0d040c2343a9e072a0d0b8cf1e0b0",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":10000.0
           },
           {
             "network": "base",
             "pool": "0x96cc4b6a75fa1dfea66091589d1f25aff3aa0318",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":10000.0
           },
           {
             "network": "base",
             "pool": "0xcea8ef6ce6235f2c2cdd13c9e8a3ed470725a638",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":10000.0
           },
           {
             "network": "base",
             "pool": "0xde5ff829fef54d1bdec957d9538a306f0ead1368",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":10000.0
           },
           {
             "network": "base",
             "pool": "0x2ce63497999f520cc2afaaadbcfc37afd9def4b0",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":10000.0
           },
           {
             "network": "base",
             "pool": "0xe722e6bce1a598e6b5d26e9975bf44140d2aa3e5",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":10000.0
           },
           {
             "network": "base",
             "pool": "0x4ef1e503c4f1e5664ac98294d0e42ddc9c0ff961",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":10000.0
           },
           {
             "network": "base",
             "pool": "0x2c206c7de24787f85b5c52d2ea339adc6d5af40f",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":10000.0
           }
         ]
       }
@@ -53579,52 +53599,62 @@
           {
             "network": "base",
             "pool": "0xd3ee0a3b349237d68517df30bfb66be971f46ad9",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":500000.0
           },
           {
             "network": "base",
             "pool": "0xb924561a57fc60041414b8471cbc99d3497097fa",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":500000.0
           },
           {
             "network": "base",
             "pool": "0x97c9750305a39e06002edd851f3d37a862ac7060",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":500000.0
           },
           {
             "network": "eth",
             "pool": "0x3ee841f47947fefbe510366e4bbb49e145484195",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":500000.0
           },
           {
             "network": "eth",
             "pool": "0xc907ba505c2e1cbc4658c395d4a2c7e6d2c32656",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":500000.0
           },
           {
             "network": "eth",
             "pool": "0x8bb9cd887dd51c5aa8d7da9e244c94bec035e47c",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":500000.0
           },
           {
             "network": "eth",
             "pool": "0x8461537a9bfc5a1df57cf825f8a58049ef61557b",
-            "reverse": false
+            "reverse": false,
+            "min_volume_usd":500000.0
           },
           {
             "network": "eth",
             "pool": "0x4628f13651ead6793f8d838b34b8f8522fb0cc52",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           },
           {
             "network": "eth",
             "pool": "0x38de22a3175708d45e7c7c64cd78479c8b56f76e",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           },
           {
             "network": "eth",
             "pool": "0xd552716f3bba4224a19d7eb37a31650d7ae10144",
-            "reverse": true
+            "reverse": true,
+            "min_volume_usd":500000.0
           }
         ]
       }
diff --git a/nix/test-environments/example-setup-01.nix b/nix/test-environments/example-setup-01.nix
index 5f1df1cc0f..0fa9d431a5 100644
--- a/nix/test-environments/example-setup-01.nix
+++ b/nix/test-environments/example-setup-01.nix
@@ -185,7 +185,7 @@ in
         interval_time_in_seconds = 10;
         capabilities = [ ];
         allowed_outbound_hosts = [
-          "https://app.geckoterminal.com"
+          "https://api.geckoterminal.com"
         ];
       };
     };


Reviews:
user: login: EmilIvanichkovv
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T10:51:06Z
user: login: EmilIvanichkovv
body: LGTM over all.

Left some comments with improvement ideas.

Tested the oracle isolated with `just start-oracle gecko-terminal`. Results are satisfying

Have **not** tested e2e as we don't have the update in the `feeds_confing_v2.json` file. Once you update it will do the e2e tests with `pricess_compose`
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T13:08:16Z
user: login: EmilIvanichkovv
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T14:11:07Z
user: login: EmilIvanichkovv
body: Ran it with process compose and got this errors
![image](https://github.com/user-attachments/assets/f66a2c2c-cfc1-4786-ae47-14ea957d33ca)

```bash
A component tried to make a HTTP request to non-allowed host 'api.geckoterminal.com'. 
```

This seems the problem

To fix you need to update https://github.com/blocksense-network/blocksense/blob/main/nix/test-environments/example-setup-01.nix#L188 
Please do in a separate commit 
```
config(nix/example-setup-01): Update `allowed_outbound_hosts` for `gecko-terminal` oracle
```

state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T14:14:24Z
user: login: EmilIvanichkovv
body: Once we merge this PR we should update the host in the `infra` repo too.

https://github.com/blocksense-network/infra/blob/main/services/blocksense/base.nix#L75
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T14:19:43Z
user: login: EmilIvanichkovv
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T14:22:49Z
user: login: EmilIvanichkovv
body: Tested e2e with process compose. All seems fine on my side.

Thanks!
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T11:48:26Z

Review comments:
path: apps/oracles/gecko-terminal/spin.toml
user: login: EmilIvanichkovv
body: It seems you should update `config/feeds_config_v2.json` too
created_at: 2025-04-10T10:51:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -29,7 +29,7 @@ data = '{"pair":{"base":"USR","quote":"USD"},"decimals":8,"category":"Crypto","m
 [component.gecko-terminal]
 source = "../../../target/wasm32-wasip1/release/gecko_terminal.wasm"
 
-allowed_outbound_hosts = ["https://app.geckoterminal.com/"]
path: apps/oracles/gecko-terminal/spin.toml
user: login: EmilIvanichkovv
body: Can we now remove `https://app.geckoterminal.com/`? It seems we do not use it
created_at: 2025-04-10T10:52:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: This makes sense to me!
created_at: 2025-04-10T10:52:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: nit: 
```suggestion
    pub fn check_volume_usd(&self) -> bool {
```
created_at: 2025-04-10T11:02:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_chunk(
+    network: &String,
+    pools: &[GeckoTerminalPool],
+) -> Result<GeckoTerminalMultipleResponce> {
+    let r = pools
+        .iter()
+        .map(|p| p.pool.clone())
+        .collect::<Vec<_>>()
+        .join(",");
+    let url = format!("https://api.geckoterminal.com/api/v2/networks/{network}/pools/multi/{r}");
+    let mut req = Request::builder();
+    req.method(Method::Get);
+    req.uri(url.as_str());
+    let resp: Response = send(req).await?;
+    let body = resp.into_body();
+    let string = String::from_utf8(body)?;
+    let mut value: GeckoTerminalMultipleResponce =
+        serde_json::from_str(&string).context("Couldn't parse Gecko terminal response properly")?;
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: You can use https://github.com/blocksense-network/blocksense/blob/main/libs/sdk/src/http.rs
like in `crypto-price-feeds` oracle
created_at: 2025-04-10T11:07:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_chunk(
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: ```suggestion
async fn fetch_pools_data_for_network(
```
?
created_at: 2025-04-10T11:14:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_chunk(
+    network: &String,
+    pools: &[GeckoTerminalPool],
+) -> Result<GeckoTerminalMultipleResponce> {
+    let r = pools
+        .iter()
+        .map(|p| p.pool.clone())
+        .collect::<Vec<_>>()
+        .join(",");
+    let url = format!("https://api.geckoterminal.com/api/v2/networks/{network}/pools/multi/{r}");
+    let mut req = Request::builder();
+    req.method(Method::Get);
+    req.uri(url.as_str());
+    let resp: Response = send(req).await?;
+    let body = resp.into_body();
+    let string = String::from_utf8(body)?;
+    let mut value: GeckoTerminalMultipleResponce =
+        serde_json::from_str(&string).context("Couldn't parse Gecko terminal response properly")?;
+    for v in value.data.iter_mut() {
+        if let Some(p) = pools
+            .iter()
+            .find(|p| p.pool.to_uppercase() == v.attributes.address.to_uppercase())
+        {
+            v.reverse = p.reverse;
+            v.feed_id = p.feed_id.clone();
+            v.network = network.clone();
+            v.min_volume_usd = p.min_volume_usd;
+        }
     }
+    Ok(value)
 }
 
 async fn fetch_all_prices(
     resourses: &Vec<FeedConfig>,
-) -> Result<HashMap<String, Vec<GeckoTerminalResponce>>> {
+) -> Result<HashMap<String, Vec<GeckoTerminalData>>> {
+    let pools_by_network = group_pools_by_network(resourses);
     let mut res = HashMap::new();
+    for network in pools_by_network.keys() {
+        if let Some(pools) = pools_by_network.get(network) {
+            for pools in pools.chunks(50) {
+                let response = fetch_chunk(network, pools).await;
+                match response {
+                    Ok(re) => {
+                        for d in re.data {
+                            if !res.contains_key(&d.feed_id) {
+                                res.insert(d.feed_id.clone(), vec![]);
+                            }
+                            if let Some(v) = res.get_mut(&d.feed_id) {
+                                v.push(d);
+                            }
+                        }
+                    }
+                    Err(e) => {
+                        println!("Error while fetching ... {e:?}");
+                    }
+                };
+            }
+        }
+    }
+    Ok(res)
+}
+
+fn group_pools_by_network(resourses: &Vec<FeedConfig>) -> HashMap<String, Vec<GeckoTerminalPool>> {
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: ```suggestion
fn group_pools_by_network(resources: &Vec<FeedConfig>) -> HashMap<String, Vec<GeckoTerminalPool>> {
```
Fix this typo here and in all other places
created_at: 2025-04-10T11:16:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_chunk(
+    network: &String,
+    pools: &[GeckoTerminalPool],
+) -> Result<GeckoTerminalMultipleResponce> {
+    let r = pools
+        .iter()
+        .map(|p| p.pool.clone())
+        .collect::<Vec<_>>()
+        .join(",");
+    let url = format!("https://api.geckoterminal.com/api/v2/networks/{network}/pools/multi/{r}");
+    let mut req = Request::builder();
+    req.method(Method::Get);
+    req.uri(url.as_str());
+    let resp: Response = send(req).await?;
+    let body = resp.into_body();
+    let string = String::from_utf8(body)?;
+    let mut value: GeckoTerminalMultipleResponce =
+        serde_json::from_str(&string).context("Couldn't parse Gecko terminal response properly")?;
+    for v in value.data.iter_mut() {
+        if let Some(p) = pools
+            .iter()
+            .find(|p| p.pool.to_uppercase() == v.attributes.address.to_uppercase())
+        {
+            v.reverse = p.reverse;
+            v.feed_id = p.feed_id.clone();
+            v.network = network.clone();
+            v.min_volume_usd = p.min_volume_usd;
+        }
     }
+    Ok(value)
 }
 
 async fn fetch_all_prices(
     resourses: &Vec<FeedConfig>,
-) -> Result<HashMap<String, Vec<GeckoTerminalResponce>>> {
+) -> Result<HashMap<String, Vec<GeckoTerminalData>>> {
+    let pools_by_network = group_pools_by_network(resourses);
     let mut res = HashMap::new();
+    for network in pools_by_network.keys() {
+        if let Some(pools) = pools_by_network.get(network) {
+            for pools in pools.chunks(50) {
+                let response = fetch_chunk(network, pools).await;
+                match response {
+                    Ok(re) => {
+                        for d in re.data {
+                            if !res.contains_key(&d.feed_id) {
+                                res.insert(d.feed_id.clone(), vec![]);
+                            }
+                            if let Some(v) = res.get_mut(&d.feed_id) {
+                                v.push(d);
+                            }
+                        }
+                    }
+                    Err(e) => {
+                        println!("Error while fetching ... {e:?}");
+                    }
+                };
+            }
+        }
+    }
+    Ok(res)
+}
+
+fn group_pools_by_network(resourses: &Vec<FeedConfig>) -> HashMap<String, Vec<GeckoTerminalPool>> {
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: ```rs
fn group_pools_by_network(resources: &Vec<FeedConfig>) -> HashMap<String, Vec<GeckoTerminalPool>> {
  let mut pools_by_network: HashMap<String, Vec<GeckoTerminalPool>> = HashMap::new();

  for config in resources {
      for pool in &config.arguments {
          let new_pool = {
              let mut cloned_pool = pool.clone();
              cloned_pool.feed_id = config.id.clone();
              cloned_pool
          };

          pools_by_network
              .entry(pool.network.clone())
              .or_insert_with(Vec::new)
              .push(new_pool);
      }
  }

  pools_by_network
}
```

This seems cleaner to me
created_at: 2025-04-10T11:39:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_chunk(
+    network: &String,
+    pools: &[GeckoTerminalPool],
+) -> Result<GeckoTerminalMultipleResponce> {
+    let r = pools
+        .iter()
+        .map(|p| p.pool.clone())
+        .collect::<Vec<_>>()
+        .join(",");
+    let url = format!("https://api.geckoterminal.com/api/v2/networks/{network}/pools/multi/{r}");
+    let mut req = Request::builder();
+    req.method(Method::Get);
+    req.uri(url.as_str());
+    let resp: Response = send(req).await?;
+    let body = resp.into_body();
+    let string = String::from_utf8(body)?;
+    let mut value: GeckoTerminalMultipleResponce =
+        serde_json::from_str(&string).context("Couldn't parse Gecko terminal response properly")?;
+    for v in value.data.iter_mut() {
+        if let Some(p) = pools
+            .iter()
+            .find(|p| p.pool.to_uppercase() == v.attributes.address.to_uppercase())
+        {
+            v.reverse = p.reverse;
+            v.feed_id = p.feed_id.clone();
+            v.network = network.clone();
+            v.min_volume_usd = p.min_volume_usd;
+        }
     }
+    Ok(value)
 }
 
 async fn fetch_all_prices(
     resourses: &Vec<FeedConfig>,
-) -> Result<HashMap<String, Vec<GeckoTerminalResponce>>> {
+) -> Result<HashMap<String, Vec<GeckoTerminalData>>> {
+    let pools_by_network = group_pools_by_network(resourses);
     let mut res = HashMap::new();
+    for network in pools_by_network.keys() {
+        if let Some(pools) = pools_by_network.get(network) {
+            for pools in pools.chunks(50) {
+                let response = fetch_chunk(network, pools).await;
+                match response {
+                    Ok(re) => {
+                        for d in re.data {
+                            if !res.contains_key(&d.feed_id) {
+                                res.insert(d.feed_id.clone(), vec![]);
+                            }
+                            if let Some(v) = res.get_mut(&d.feed_id) {
+                                v.push(d);
+                            }
+                        }
+                    }
+                    Err(e) => {
+                        println!("Error while fetching ... {e:?}");
+                    }
+                };
+            }
+        }
+    }
+    Ok(res)
+}
+
+fn group_pools_by_network(resourses: &Vec<FeedConfig>) -> HashMap<String, Vec<GeckoTerminalPool>> {
+    let mut pools_by_network: HashMap<String, Vec<GeckoTerminalPool>> = HashMap::new();
     for config in resourses {
-        let mut v = vec![];
         for pool in config.arguments.iter() {
-            match pool.fetch().await {
-                Ok(response) => {
-                    v.push(response);
-                }
-                Err(e) => {
-                    println!("Error {e:?} when fetching from {pool:?}");
-                }
-            };
+            if !pools_by_network.contains_key(&pool.network) {
+                pools_by_network.insert(pool.network.clone(), vec![]);
+            }
+            if let Some(p) = pools_by_network.get_mut(&pool.network) {
+                let mut new_pool = pool.clone();
+                new_pool.feed_id = config.id.clone();
+                p.push(new_pool);
+            }
         }
-        res.insert(config.id.clone(), v);
     }
-    Ok(res)
+    pools_by_network
 }
 
-fn process_results(reponses: &HashMap<String, Vec<GeckoTerminalResponce>>) -> Result<Payload> {
+fn process_results(reponses: &HashMap<String, Vec<GeckoTerminalData>>) -> Result<Payload> {
     let mut payload: Payload = Payload::new();
-    for (id, responses) in reponses.iter() {
+    for (id, vec_data) in reponses.iter() {
         let mut total: f64 = 0.0f64;
         let mut total_weight: f64 = 0.0f64;
         let mut total_weighted_price: f64 = 0.0f64;
         let mut count: i32 = 0;
-        for response in responses {
-            let price = response.get_price();
-            let weight = response
-                .data
-                .attributes
-                .historical_data
-                .last_24h
-                .volume_in_usd;
-            total += price;
-            total_weighted_price += price * weight;
-            total_weight += weight;
-            count += 1;
+        for data in vec_data {
+            if data.test_volume_usd() {
+                let price = data.get_price();
+
+                let weight = data.attributes.volume_usd.h24;
+                total += price;
+                total_weighted_price += price * weight;
+                total_weight += weight;
+                count += 1;
+            }
         }
-        let price = if count == 1 {
-            total
+        if count > 0 {
+            let price = if count == 1 {
+                total
+            } else {
+                total_weighted_price / total_weight
+            };
+            payload.values.push(DataFeedResult {
+                id: id.clone(),
+                value: DataFeedResultValue::Numerical(price),
+            });
         } else {
-            total_weighted_price / total_weight
-        };
-        payload.values.push(DataFeedResult {
-            id: id.clone(),
-            value: DataFeedResultValue::Numerical(price),
-        });
+            payload.values.push(DataFeedResult {
+                id: id.clone(),
+                value: DataFeedResultValue::Error(
+                    "Not enough volume to reliably average prices".to_string(),
+                ),
+            });
+        }
     }
     Ok(payload)
 }
 
+fn print_responses(reponses: &HashMap<String, Vec<GeckoTerminalData>>) {
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: Really like the idea of having this table. Here is an update to improve the visual representation. Code snippet below

| Before | After |
| -------- | ------- |
| ![image](https://github.com/user-attachments/assets/4550a413-2dd6-4d8a-8dbc-b18dd2a64ceb) | ![image](https://github.com/user-attachments/assets/ec405f2d-0632-4e2d-a0cb-550163f4bb4e) |
created_at: 2025-04-10T11:58:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_chunk(
+    network: &String,
+    pools: &[GeckoTerminalPool],
+) -> Result<GeckoTerminalMultipleResponce> {
+    let r = pools
+        .iter()
+        .map(|p| p.pool.clone())
+        .collect::<Vec<_>>()
+        .join(",");
+    let url = format!("https://api.geckoterminal.com/api/v2/networks/{network}/pools/multi/{r}");
+    let mut req = Request::builder();
+    req.method(Method::Get);
+    req.uri(url.as_str());
+    let resp: Response = send(req).await?;
+    let body = resp.into_body();
+    let string = String::from_utf8(body)?;
+    let mut value: GeckoTerminalMultipleResponce =
+        serde_json::from_str(&string).context("Couldn't parse Gecko terminal response properly")?;
+    for v in value.data.iter_mut() {
+        if let Some(p) = pools
+            .iter()
+            .find(|p| p.pool.to_uppercase() == v.attributes.address.to_uppercase())
+        {
+            v.reverse = p.reverse;
+            v.feed_id = p.feed_id.clone();
+            v.network = network.clone();
+            v.min_volume_usd = p.min_volume_usd;
+        }
     }
+    Ok(value)
 }
 
 async fn fetch_all_prices(
     resourses: &Vec<FeedConfig>,
-) -> Result<HashMap<String, Vec<GeckoTerminalResponce>>> {
+) -> Result<HashMap<String, Vec<GeckoTerminalData>>> {
+    let pools_by_network = group_pools_by_network(resourses);
     let mut res = HashMap::new();
+    for network in pools_by_network.keys() {
+        if let Some(pools) = pools_by_network.get(network) {
+            for pools in pools.chunks(50) {
+                let response = fetch_chunk(network, pools).await;
+                match response {
+                    Ok(re) => {
+                        for d in re.data {
+                            if !res.contains_key(&d.feed_id) {
+                                res.insert(d.feed_id.clone(), vec![]);
+                            }
+                            if let Some(v) = res.get_mut(&d.feed_id) {
+                                v.push(d);
+                            }
+                        }
+                    }
+                    Err(e) => {
+                        println!("Error while fetching ... {e:?}");
+                    }
+                };
+            }
+        }
+    }
+    Ok(res)
+}
+
+fn group_pools_by_network(resourses: &Vec<FeedConfig>) -> HashMap<String, Vec<GeckoTerminalPool>> {
+    let mut pools_by_network: HashMap<String, Vec<GeckoTerminalPool>> = HashMap::new();
     for config in resourses {
-        let mut v = vec![];
         for pool in config.arguments.iter() {
-            match pool.fetch().await {
-                Ok(response) => {
-                    v.push(response);
-                }
-                Err(e) => {
-                    println!("Error {e:?} when fetching from {pool:?}");
-                }
-            };
+            if !pools_by_network.contains_key(&pool.network) {
+                pools_by_network.insert(pool.network.clone(), vec![]);
+            }
+            if let Some(p) = pools_by_network.get_mut(&pool.network) {
+                let mut new_pool = pool.clone();
+                new_pool.feed_id = config.id.clone();
+                p.push(new_pool);
+            }
         }
-        res.insert(config.id.clone(), v);
     }
-    Ok(res)
+    pools_by_network
 }
 
-fn process_results(reponses: &HashMap<String, Vec<GeckoTerminalResponce>>) -> Result<Payload> {
+fn process_results(reponses: &HashMap<String, Vec<GeckoTerminalData>>) -> Result<Payload> {
     let mut payload: Payload = Payload::new();
-    for (id, responses) in reponses.iter() {
+    for (id, vec_data) in reponses.iter() {
         let mut total: f64 = 0.0f64;
         let mut total_weight: f64 = 0.0f64;
         let mut total_weighted_price: f64 = 0.0f64;
         let mut count: i32 = 0;
-        for response in responses {
-            let price = response.get_price();
-            let weight = response
-                .data
-                .attributes
-                .historical_data
-                .last_24h
-                .volume_in_usd;
-            total += price;
-            total_weighted_price += price * weight;
-            total_weight += weight;
-            count += 1;
+        for data in vec_data {
+            if data.test_volume_usd() {
+                let price = data.get_price();
+
+                let weight = data.attributes.volume_usd.h24;
+                total += price;
+                total_weighted_price += price * weight;
+                total_weight += weight;
+                count += 1;
+            }
         }
-        let price = if count == 1 {
-            total
+        if count > 0 {
+            let price = if count == 1 {
+                total
+            } else {
+                total_weighted_price / total_weight
+            };
+            payload.values.push(DataFeedResult {
+                id: id.clone(),
+                value: DataFeedResultValue::Numerical(price),
+            });
         } else {
-            total_weighted_price / total_weight
-        };
-        payload.values.push(DataFeedResult {
-            id: id.clone(),
-            value: DataFeedResultValue::Numerical(price),
-        });
+            payload.values.push(DataFeedResult {
+                id: id.clone(),
+                value: DataFeedResultValue::Error(
+                    "Not enough volume to reliably average prices".to_string(),
+                ),
+            });
+        }
     }
     Ok(payload)
 }
 
+fn print_responses(reponses: &HashMap<String, Vec<GeckoTerminalData>>) {
+    let mut table = Table::new();
+    table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
+
+    table.set_titles(Row::new(vec![
+        Cell::new("Feed ID").style_spec("bc"),
+        Cell::new("Network").style_spec("bc"),
+        Cell::new("Name").style_spec("bc"),
+        Cell::new("Price[USD]").style_spec("bc"),
+        Cell::new("Volume[USD]").style_spec("bc"),
+        Cell::new("Include").style_spec("bc"),
+    ]));
+
+    for data in reponses.values() {
+        for d in data {
+            let price = d.get_price();
+            let include = d.test_volume_usd();
+            table.add_row(Row::new(vec![
+                Cell::new(&d.feed_id).style_spec("r"),
+                Cell::new(&d.network).style_spec("l"),
+                Cell::new(&d.attributes.name).style_spec("l"),
+                Cell::new(&price.to_string()).style_spec("r"),
+                Cell::new(&d.attributes.volume_usd.h24.to_string()).style_spec("r"),
+                Cell::new(&include.to_string()).style_spec("r"),
+            ]));
+        }
+    }
+    table.printstd();
+}
+
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: ```suggestion
fn print_responses(reponses: &HashMap<String, Vec<GeckoTerminalData>>) {
    let mut table = Table::new();
    table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);

    table.set_titles(Row::new(vec![
        Cell::new("Feed ID").style_spec("bc"),
        Cell::new("Network").style_spec("bc"),
        Cell::new("Name").style_spec("bc"),
        Cell::new("Price[USD]").style_spec("bc"),
        Cell::new("Volume[USD]").style_spec("bc"),
        Cell::new("Include").style_spec("bc"),
    ]));

    let mut previous_feed_id: Option<&String> = None;

    for data in reponses.values() {
        for d in data {
            // Check if the feed_id has changed
            if let Some(prev_id) = previous_feed_id {
                if prev_id != &d.feed_id {
                    // Add an empty row as a separator
                    table.add_empty_row();
                }
            }

            // Add the current row
            let price = d.get_price();
            let include = d.test_volume_usd();
            table.add_row(Row::new(vec![
                Cell::new(&d.feed_id).style_spec("r"),
                Cell::new(&d.network).style_spec("l"),
                Cell::new(&d.attributes.name).style_spec("l"),
                Cell::new(&price.to_string()).style_spec("r"),
                Cell::new(&d.attributes.volume_usd.h24.to_string()).style_spec("r"),
                Cell::new(&include.to_string()).style_spec("r"),
            ]));

            // Update the previous_feed_id
            previous_feed_id = Some(&d.feed_id);
        }
    }

    table.printstd();
}
```

Here is my suggestion.
> Note: This assumes the data is sorted by ID. If it is not, please do
created_at: 2025-04-10T12:01:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_chunk(
+    network: &String,
+    pools: &[GeckoTerminalPool],
+) -> Result<GeckoTerminalMultipleResponce> {
+    let r = pools
+        .iter()
+        .map(|p| p.pool.clone())
+        .collect::<Vec<_>>()
+        .join(",");
+    let url = format!("https://api.geckoterminal.com/api/v2/networks/{network}/pools/multi/{r}");
+    let mut req = Request::builder();
+    req.method(Method::Get);
+    req.uri(url.as_str());
+    let resp: Response = send(req).await?;
+    let body = resp.into_body();
+    let string = String::from_utf8(body)?;
+    let mut value: GeckoTerminalMultipleResponce =
+        serde_json::from_str(&string).context("Couldn't parse Gecko terminal response properly")?;
+    for v in value.data.iter_mut() {
+        if let Some(p) = pools
+            .iter()
+            .find(|p| p.pool.to_uppercase() == v.attributes.address.to_uppercase())
+        {
+            v.reverse = p.reverse;
+            v.feed_id = p.feed_id.clone();
+            v.network = network.clone();
+            v.min_volume_usd = p.min_volume_usd;
+        }
     }
+    Ok(value)
 }
 
 async fn fetch_all_prices(
     resourses: &Vec<FeedConfig>,
-) -> Result<HashMap<String, Vec<GeckoTerminalResponce>>> {
+) -> Result<HashMap<String, Vec<GeckoTerminalData>>> {
+    let pools_by_network = group_pools_by_network(resourses);
     let mut res = HashMap::new();
+    for network in pools_by_network.keys() {
+        if let Some(pools) = pools_by_network.get(network) {
+            for pools in pools.chunks(50) {
+                let response = fetch_chunk(network, pools).await;
+                match response {
+                    Ok(re) => {
+                        for d in re.data {
+                            if !res.contains_key(&d.feed_id) {
+                                res.insert(d.feed_id.clone(), vec![]);
+                            }
+                            if let Some(v) = res.get_mut(&d.feed_id) {
+                                v.push(d);
+                            }
+                        }
+                    }
+                    Err(e) => {
+                        println!("Error while fetching ... {e:?}");
+                    }
+                };
+            }
+        }
+    }
+    Ok(res)
+}
+
+fn group_pools_by_network(resourses: &Vec<FeedConfig>) -> HashMap<String, Vec<GeckoTerminalPool>> {
+    let mut pools_by_network: HashMap<String, Vec<GeckoTerminalPool>> = HashMap::new();
     for config in resourses {
-        let mut v = vec![];
         for pool in config.arguments.iter() {
-            match pool.fetch().await {
-                Ok(response) => {
-                    v.push(response);
-                }
-                Err(e) => {
-                    println!("Error {e:?} when fetching from {pool:?}");
-                }
-            };
+            if !pools_by_network.contains_key(&pool.network) {
+                pools_by_network.insert(pool.network.clone(), vec![]);
+            }
+            if let Some(p) = pools_by_network.get_mut(&pool.network) {
+                let mut new_pool = pool.clone();
+                new_pool.feed_id = config.id.clone();
+                p.push(new_pool);
+            }
         }
-        res.insert(config.id.clone(), v);
     }
-    Ok(res)
+    pools_by_network
 }
 
-fn process_results(reponses: &HashMap<String, Vec<GeckoTerminalResponce>>) -> Result<Payload> {
+fn process_results(reponses: &HashMap<String, Vec<GeckoTerminalData>>) -> Result<Payload> {
     let mut payload: Payload = Payload::new();
-    for (id, responses) in reponses.iter() {
+    for (id, vec_data) in reponses.iter() {
         let mut total: f64 = 0.0f64;
         let mut total_weight: f64 = 0.0f64;
         let mut total_weighted_price: f64 = 0.0f64;
         let mut count: i32 = 0;
-        for response in responses {
-            let price = response.get_price();
-            let weight = response
-                .data
-                .attributes
-                .historical_data
-                .last_24h
-                .volume_in_usd;
-            total += price;
-            total_weighted_price += price * weight;
-            total_weight += weight;
-            count += 1;
+        for data in vec_data {
+            if data.test_volume_usd() {
+                let price = data.get_price();
+
+                let weight = data.attributes.volume_usd.h24;
+                total += price;
+                total_weighted_price += price * weight;
+                total_weight += weight;
+                count += 1;
+            }
         }
-        let price = if count == 1 {
-            total
+        if count > 0 {
+            let price = if count == 1 {
+                total
+            } else {
+                total_weighted_price / total_weight
+            };
+            payload.values.push(DataFeedResult {
+                id: id.clone(),
+                value: DataFeedResultValue::Numerical(price),
+            });
         } else {
-            total_weighted_price / total_weight
-        };
-        payload.values.push(DataFeedResult {
-            id: id.clone(),
-            value: DataFeedResultValue::Numerical(price),
-        });
+            payload.values.push(DataFeedResult {
+                id: id.clone(),
+                value: DataFeedResultValue::Error(
+                    "Not enough volume to reliably average prices".to_string(),
+                ),
+            });
+        }
     }
     Ok(payload)
 }
 
+fn print_responses(reponses: &HashMap<String, Vec<GeckoTerminalData>>) {
+    let mut table = Table::new();
+    table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
+
+    table.set_titles(Row::new(vec![
+        Cell::new("Feed ID").style_spec("bc"),
+        Cell::new("Network").style_spec("bc"),
+        Cell::new("Name").style_spec("bc"),
+        Cell::new("Price[USD]").style_spec("bc"),
+        Cell::new("Volume[USD]").style_spec("bc"),
+        Cell::new("Include").style_spec("bc"),
+    ]));
+
+    for data in reponses.values() {
+        for d in data {
+            let price = d.get_price();
+            let include = d.test_volume_usd();
+            table.add_row(Row::new(vec![
+                Cell::new(&d.feed_id).style_spec("r"),
+                Cell::new(&d.network).style_spec("l"),
+                Cell::new(&d.attributes.name).style_spec("l"),
+                Cell::new(&price.to_string()).style_spec("r"),
+                Cell::new(&d.attributes.volume_usd.h24.to_string()).style_spec("r"),
+                Cell::new(&include.to_string()).style_spec("r"),
+            ]));
+        }
+    }
+    table.printstd();
+}
+
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: Also, we can include the  `reverse` column
created_at: 2025-04-10T12:40:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_chunk(
+    network: &String,
+    pools: &[GeckoTerminalPool],
+) -> Result<GeckoTerminalMultipleResponce> {
+    let r = pools
+        .iter()
+        .map(|p| p.pool.clone())
+        .collect::<Vec<_>>()
+        .join(",");
+    let url = format!("https://api.geckoterminal.com/api/v2/networks/{network}/pools/multi/{r}");
+    let mut req = Request::builder();
+    req.method(Method::Get);
+    req.uri(url.as_str());
+    let resp: Response = send(req).await?;
+    let body = resp.into_body();
+    let string = String::from_utf8(body)?;
+    let mut value: GeckoTerminalMultipleResponce =
+        serde_json::from_str(&string).context("Couldn't parse Gecko terminal response properly")?;
+    for v in value.data.iter_mut() {
+        if let Some(p) = pools
+            .iter()
+            .find(|p| p.pool.to_uppercase() == v.attributes.address.to_uppercase())
+        {
+            v.reverse = p.reverse;
+            v.feed_id = p.feed_id.clone();
+            v.network = network.clone();
+            v.min_volume_usd = p.min_volume_usd;
+        }
     }
+    Ok(value)
 }
 
 async fn fetch_all_prices(
     resourses: &Vec<FeedConfig>,
-) -> Result<HashMap<String, Vec<GeckoTerminalResponce>>> {
+) -> Result<HashMap<String, Vec<GeckoTerminalData>>> {
+    let pools_by_network = group_pools_by_network(resourses);
     let mut res = HashMap::new();
+    for network in pools_by_network.keys() {
+        if let Some(pools) = pools_by_network.get(network) {
+            for pools in pools.chunks(50) {
+                let response = fetch_chunk(network, pools).await;
+                match response {
+                    Ok(re) => {
+                        for d in re.data {
+                            if !res.contains_key(&d.feed_id) {
+                                res.insert(d.feed_id.clone(), vec![]);
+                            }
+                            if let Some(v) = res.get_mut(&d.feed_id) {
+                                v.push(d);
+                            }
+                        }
+                    }
+                    Err(e) => {
+                        println!("Error while fetching ... {e:?}");
+                    }
+                };
+            }
+        }
+    }
+    Ok(res)
+}
+
+fn group_pools_by_network(resourses: &Vec<FeedConfig>) -> HashMap<String, Vec<GeckoTerminalPool>> {
+    let mut pools_by_network: HashMap<String, Vec<GeckoTerminalPool>> = HashMap::new();
     for config in resourses {
-        let mut v = vec![];
         for pool in config.arguments.iter() {
-            match pool.fetch().await {
-                Ok(response) => {
-                    v.push(response);
-                }
-                Err(e) => {
-                    println!("Error {e:?} when fetching from {pool:?}");
-                }
-            };
+            if !pools_by_network.contains_key(&pool.network) {
+                pools_by_network.insert(pool.network.clone(), vec![]);
+            }
+            if let Some(p) = pools_by_network.get_mut(&pool.network) {
+                let mut new_pool = pool.clone();
+                new_pool.feed_id = config.id.clone();
+                p.push(new_pool);
+            }
         }
-        res.insert(config.id.clone(), v);
     }
-    Ok(res)
+    pools_by_network
 }
 
-fn process_results(reponses: &HashMap<String, Vec<GeckoTerminalResponce>>) -> Result<Payload> {
+fn process_results(reponses: &HashMap<String, Vec<GeckoTerminalData>>) -> Result<Payload> {
     let mut payload: Payload = Payload::new();
-    for (id, responses) in reponses.iter() {
+    for (id, vec_data) in reponses.iter() {
         let mut total: f64 = 0.0f64;
         let mut total_weight: f64 = 0.0f64;
         let mut total_weighted_price: f64 = 0.0f64;
         let mut count: i32 = 0;
-        for response in responses {
-            let price = response.get_price();
-            let weight = response
-                .data
-                .attributes
-                .historical_data
-                .last_24h
-                .volume_in_usd;
-            total += price;
-            total_weighted_price += price * weight;
-            total_weight += weight;
-            count += 1;
+        for data in vec_data {
+            if data.test_volume_usd() {
+                let price = data.get_price();
+
+                let weight = data.attributes.volume_usd.h24;
+                total += price;
+                total_weighted_price += price * weight;
+                total_weight += weight;
+                count += 1;
+            }
         }
-        let price = if count == 1 {
-            total
+        if count > 0 {
+            let price = if count == 1 {
+                total
+            } else {
+                total_weighted_price / total_weight
+            };
+            payload.values.push(DataFeedResult {
+                id: id.clone(),
+                value: DataFeedResultValue::Numerical(price),
+            });
         } else {
-            total_weighted_price / total_weight
-        };
-        payload.values.push(DataFeedResult {
-            id: id.clone(),
-            value: DataFeedResultValue::Numerical(price),
-        });
+            payload.values.push(DataFeedResult {
+                id: id.clone(),
+                value: DataFeedResultValue::Error(
+                    "Not enough volume to reliably average prices".to_string(),
+                ),
+            });
+        }
     }
     Ok(payload)
 }
 
+fn print_responses(reponses: &HashMap<String, Vec<GeckoTerminalData>>) {
+    let mut table = Table::new();
+    table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
+
+    table.set_titles(Row::new(vec![
+        Cell::new("Feed ID").style_spec("bc"),
+        Cell::new("Network").style_spec("bc"),
+        Cell::new("Name").style_spec("bc"),
+        Cell::new("Price[USD]").style_spec("bc"),
+        Cell::new("Volume[USD]").style_spec("bc"),
+        Cell::new("Include").style_spec("bc"),
+    ]));
+
+    for data in reponses.values() {
+        for d in data {
+            let price = d.get_price();
+            let include = d.test_volume_usd();
+            table.add_row(Row::new(vec![
+                Cell::new(&d.feed_id).style_spec("r"),
+                Cell::new(&d.network).style_spec("l"),
+                Cell::new(&d.attributes.name).style_spec("l"),
+                Cell::new(&price.to_string()).style_spec("r"),
+                Cell::new(&d.attributes.volume_usd.h24.to_string()).style_spec("r"),
+                Cell::new(&include.to_string()).style_spec("r"),
+            ]));
+        }
+    }
+    table.printstd();
+}
+
 fn print_results(
     resourses: &[FeedConfig],
-    reponses: &HashMap<String, Vec<GeckoTerminalResponce>>,
+    responses: &HashMap<String, Vec<GeckoTerminalData>>,
     payload: &Payload,
 ) {
+    print_responses(responses);
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: We can sort the IDs here too
created_at: 2025-04-10T12:43:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_chunk(
+    network: &String,
+    pools: &[GeckoTerminalPool],
+) -> Result<GeckoTerminalMultipleResponce> {
+    let r = pools
+        .iter()
+        .map(|p| p.pool.clone())
+        .collect::<Vec<_>>()
+        .join(",");
+    let url = format!("https://api.geckoterminal.com/api/v2/networks/{network}/pools/multi/{r}");
+    let mut req = Request::builder();
+    req.method(Method::Get);
+    req.uri(url.as_str());
+    let resp: Response = send(req).await?;
+    let body = resp.into_body();
+    let string = String::from_utf8(body)?;
+    let mut value: GeckoTerminalMultipleResponce =
+        serde_json::from_str(&string).context("Couldn't parse Gecko terminal response properly")?;
+    for v in value.data.iter_mut() {
+        if let Some(p) = pools
+            .iter()
+            .find(|p| p.pool.to_uppercase() == v.attributes.address.to_uppercase())
+        {
+            v.reverse = p.reverse;
+            v.feed_id = p.feed_id.clone();
+            v.network = network.clone();
+            v.min_volume_usd = p.min_volume_usd;
+        }
     }
+    Ok(value)
 }
 
 async fn fetch_all_prices(
     resourses: &Vec<FeedConfig>,
-) -> Result<HashMap<String, Vec<GeckoTerminalResponce>>> {
+) -> Result<HashMap<String, Vec<GeckoTerminalData>>> {
+    let pools_by_network = group_pools_by_network(resourses);
     let mut res = HashMap::new();
+    for network in pools_by_network.keys() {
+        if let Some(pools) = pools_by_network.get(network) {
+            for pools in pools.chunks(50) {
+                let response = fetch_chunk(network, pools).await;
+                match response {
+                    Ok(re) => {
+                        for d in re.data {
+                            if !res.contains_key(&d.feed_id) {
+                                res.insert(d.feed_id.clone(), vec![]);
+                            }
+                            if let Some(v) = res.get_mut(&d.feed_id) {
+                                v.push(d);
+                            }
+                        }
+                    }
+                    Err(e) => {
+                        println!("Error while fetching ... {e:?}");
+                    }
+                };
+            }
+        }
+    }
+    Ok(res)
+}
+
+fn group_pools_by_network(resourses: &Vec<FeedConfig>) -> HashMap<String, Vec<GeckoTerminalPool>> {
+    let mut pools_by_network: HashMap<String, Vec<GeckoTerminalPool>> = HashMap::new();
     for config in resourses {
-        let mut v = vec![];
         for pool in config.arguments.iter() {
-            match pool.fetch().await {
-                Ok(response) => {
-                    v.push(response);
-                }
-                Err(e) => {
-                    println!("Error {e:?} when fetching from {pool:?}");
-                }
-            };
+            if !pools_by_network.contains_key(&pool.network) {
+                pools_by_network.insert(pool.network.clone(), vec![]);
+            }
+            if let Some(p) = pools_by_network.get_mut(&pool.network) {
+                let mut new_pool = pool.clone();
+                new_pool.feed_id = config.id.clone();
+                p.push(new_pool);
+            }
         }
-        res.insert(config.id.clone(), v);
     }
-    Ok(res)
+    pools_by_network
 }
 
-fn process_results(reponses: &HashMap<String, Vec<GeckoTerminalResponce>>) -> Result<Payload> {
+fn process_results(reponses: &HashMap<String, Vec<GeckoTerminalData>>) -> Result<Payload> {
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: if we define and use a Type for reasons this might improve the code readability and maintenance. The reason to write this comment is that I was not sure what this HashMap represents, and had to print it and see if it is a `Id` -> `response data` 
created_at: 2025-04-10T12:51:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: ```suggestion
pub struct GeckoTerminalFeedConfig {
```

Isn't this a better and more self-explanatory name
created_at: 2025-04-10T12:56:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_chunk(
+    network: &String,
+    pools: &[GeckoTerminalPool],
+) -> Result<GeckoTerminalMultipleResponce> {
+    let r = pools
+        .iter()
+        .map(|p| p.pool.clone())
+        .collect::<Vec<_>>()
+        .join(",");
+    let url = format!("https://api.geckoterminal.com/api/v2/networks/{network}/pools/multi/{r}");
+    let mut req = Request::builder();
+    req.method(Method::Get);
+    req.uri(url.as_str());
+    let resp: Response = send(req).await?;
+    let body = resp.into_body();
+    let string = String::from_utf8(body)?;
+    let mut value: GeckoTerminalMultipleResponce =
+        serde_json::from_str(&string).context("Couldn't parse Gecko terminal response properly")?;
+    for v in value.data.iter_mut() {
+        if let Some(p) = pools
+            .iter()
+            .find(|p| p.pool.to_uppercase() == v.attributes.address.to_uppercase())
+        {
+            v.reverse = p.reverse;
+            v.feed_id = p.feed_id.clone();
+            v.network = network.clone();
+            v.min_volume_usd = p.min_volume_usd;
+        }
     }
+    Ok(value)
 }
 
 async fn fetch_all_prices(
     resourses: &Vec<FeedConfig>,
-) -> Result<HashMap<String, Vec<GeckoTerminalResponce>>> {
+) -> Result<HashMap<String, Vec<GeckoTerminalData>>> {
+    let pools_by_network = group_pools_by_network(resourses);
     let mut res = HashMap::new();
+    for network in pools_by_network.keys() {
+        if let Some(pools) = pools_by_network.get(network) {
+            for pools in pools.chunks(50) {
+                let response = fetch_chunk(network, pools).await;
+                match response {
+                    Ok(re) => {
+                        for d in re.data {
+                            if !res.contains_key(&d.feed_id) {
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: Here we can also use entry. Not sure if this will be an improvement tho
created_at: 2025-04-10T12:58:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,165 +14,266 @@ use serde_this_or_that::as_f64;
 pub struct PoolAttributes {
     pub address: String,
     pub name: String,
+    pub volume_usd: VolumeUSD,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
+    pub base_token_price_usd: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_target_token: f64,
-    pub historical_data: HistoricalData,
-}
-
-#[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalVolumeInfo {
-    pub swaps_count: u128,
-    pub buyers_count: u128,
+    pub base_token_price_native_currency: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_usd: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub quote_token_price_native_currency: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub price_in_usd: f64,
-    pub sellers_count: u128,
+    pub base_token_price_quote_token: f64,
     #[serde(deserialize_with = "as_f64")]
-    pub volume_in_usd: f64,
-    pub buy_swaps_count: u128,
-    pub sell_swaps_count: u128,
+    pub quote_token_price_base_token: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct HistoricalData {
-    pub last_5m: HistoricalVolumeInfo,
-    pub last_15m: HistoricalVolumeInfo,
-    pub last_30m: HistoricalVolumeInfo,
-    pub last_1h: HistoricalVolumeInfo,
-    pub last_6h: HistoricalVolumeInfo,
-    pub last_24h: HistoricalVolumeInfo,
+pub struct VolumeUSD {
+    #[serde(deserialize_with = "as_f64")]
+    pub m5: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m15: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub m30: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h1: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h6: f64,
+    #[serde(deserialize_with = "as_f64")]
+    pub h24: f64,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalData {
-    pub id: String,
+    #[serde(default)]
+    pub feed_id: String,
+    #[serde(default)]
+    pub network: String,
     pub attributes: PoolAttributes,
+    #[serde(default)]
+    pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
 pub struct GeckoTerminalResponce {
     pub data: GeckoTerminalData,
-    #[serde(default)]
-    pub reverse: bool,
 }
 
-impl GeckoTerminalResponce {
-    pub fn reserve_price_in_usd(&self) -> f64 {
-        self.data.attributes.price_in_usd / self.data.attributes.price_in_target_token
-    }
+#[derive(Debug, Default, Clone, Deserialize, Serialize)]
+pub struct GeckoTerminalMultipleResponce {
+    pub data: Vec<GeckoTerminalData>,
+}
 
+impl GeckoTerminalData {
     pub fn get_price(&self) -> f64 {
         if self.reverse {
-            self.reserve_price_in_usd()
+            self.attributes.quote_token_price_usd
+        } else {
+            self.attributes.base_token_price_usd
+        }
+    }
+    pub fn test_volume_usd(&self) -> bool {
+        if let Some(v) = self.min_volume_usd {
+            self.attributes.volume_usd.h24 > v
         } else {
-            self.data.attributes.price_in_usd
+            true
         }
     }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
 pub struct GeckoTerminalPool {
+    #[serde(default)]
+    pub feed_id: String,
     pub network: String,
     pub pool: String,
     pub reverse: bool,
+    #[serde(default)]
+    pub min_volume_usd: Option<f64>,
 }
 
-impl GeckoTerminalPool {
-    pub async fn fetch(&self) -> Result<GeckoTerminalResponce> {
-        let network = &self.network;
-        let pool = &self.pool;
-        let url = format!("https://app.geckoterminal.com/api/p1/{network}/pools/{pool}");
-        let mut req = Request::builder();
-        req.method(Method::Get);
-        req.uri(url.as_str());
-        let resp: Response = send(req).await?;
-        let body = resp.into_body();
-        let string = String::from_utf8(body)?;
-        let mut value: GeckoTerminalResponce = serde_json::from_str(&string)
-            .context("Couldn't parse Gecko terminal response properly")?;
-        value.reverse = self.reverse;
-        Ok(value)
+async fn fetch_chunk(
+    network: &String,
+    pools: &[GeckoTerminalPool],
+) -> Result<GeckoTerminalMultipleResponce> {
+    let r = pools
+        .iter()
+        .map(|p| p.pool.clone())
+        .collect::<Vec<_>>()
+        .join(",");
+    let url = format!("https://api.geckoterminal.com/api/v2/networks/{network}/pools/multi/{r}");
+    let mut req = Request::builder();
+    req.method(Method::Get);
+    req.uri(url.as_str());
+    let resp: Response = send(req).await?;
+    let body = resp.into_body();
+    let string = String::from_utf8(body)?;
+    let mut value: GeckoTerminalMultipleResponce =
+        serde_json::from_str(&string).context("Couldn't parse Gecko terminal response properly")?;
+    for v in value.data.iter_mut() {
+        if let Some(p) = pools
+            .iter()
+            .find(|p| p.pool.to_uppercase() == v.attributes.address.to_uppercase())
+        {
+            v.reverse = p.reverse;
+            v.feed_id = p.feed_id.clone();
+            v.network = network.clone();
+            v.min_volume_usd = p.min_volume_usd;
+        }
     }
+    Ok(value)
 }
 
 async fn fetch_all_prices(
     resourses: &Vec<FeedConfig>,
-) -> Result<HashMap<String, Vec<GeckoTerminalResponce>>> {
+) -> Result<HashMap<String, Vec<GeckoTerminalData>>> {
+    let pools_by_network = group_pools_by_network(resourses);
     let mut res = HashMap::new();
+    for network in pools_by_network.keys() {
+        if let Some(pools) = pools_by_network.get(network) {
+            for pools in pools.chunks(50) {
+                let response = fetch_chunk(network, pools).await;
+                match response {
+                    Ok(re) => {
+                        for d in re.data {
+                            if !res.contains_key(&d.feed_id) {
+                                res.insert(d.feed_id.clone(), vec![]);
+                            }
+                            if let Some(v) = res.get_mut(&d.feed_id) {
+                                v.push(d);
+                            }
+                        }
+                    }
+                    Err(e) => {
+                        println!("Error while fetching ... {e:?}");
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: Add info of the feed_id, network and pool for which we get the error
created_at: 2025-04-10T13:00:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -46,7 +48,7 @@ pub struct VolumeUSD {
 }
 
 #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-pub struct GeckoTerminalData {
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: That was ok. In next comment I explain what I meant
created_at: 2025-04-10T14:09:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -130,13 +126,15 @@ async fn fetch_chunk(
 
 async fn fetch_all_prices(
     resourses: &Vec<FeedConfig>,
-) -> Result<HashMap<String, Vec<GeckoTerminalData>>> {
+) -> Result<HashMap<String, Vec<ResponseData>>> {
path: apps/oracles/gecko-terminal/src/lib.rs
user: login: EmilIvanichkovv
body: What i meant is to define type 
```ts
type GeckoTerminalDataForFeed = HashMap<String, Vec<GeckoTerminalData>>;
```

And then use it here
created_at: 2025-04-10T14:10:51Z
author_association: CONTRIBUTOR
path: apps/oracles/gecko-terminal/spin.toml
user: login: EmilIvanichkovv
body: These are the correct values for here
```
[[trigger.oracle.data_feeds]]
id = "1000000"
data = '{"pair":{"base":"WMON","quote":"USD"},"decimals":8,"category":"Crypto","market_hours":"Crypto","arguments":[{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x264e9b75723d75e3c607627d8e21d2c758db4c80","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x8552706d9a27013f20ea0f9df8e20b61e283d2d3","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x5323821de342c56b80c99fbc7cd725f2da8eb87b","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x6e4b7be5ef7f8950c76baa0bd90125bc9b33c8db","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x212fde77a42d55f980d0a0304e7eebe1e999c60f","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0xc0ce32eee0eb8bf24fa2b00923a78abc5002f91e","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0x786f4aa162457ecdf8fa4657759fa3e86c9394ff","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0xf2afc5aa9965cdb2d4be94823c98411291b61297","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0xf22d36b6bee8a7fd51def4e3badf35a8733b284f","reverse":true},{"min_volume_usd":500000.0,"network":"monad-testnet","pool":"0xe8a806ae6ecb1f02063e21c6f0579b145399ee5f","reverse":true}]}'

[[trigger.oracle.data_feeds]]
id = "1000001"
data = '{"pair":{"base":"USDZ","quote":"USD"},"decimals":8,"category":"Crypto","market_hours":"Crypto","arguments":[{"min_volume_usd":10000.0,"network":"base","pool":"0xcf88b8bf7ccce2d836878e538197eb20fc673bce","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0x6d0b9c9e92a3de30081563c3657b5258b3ffa38b","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0xebf0e4da26a0d040c2343a9e072a0d0b8cf1e0b0","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0x96cc4b6a75fa1dfea66091589d1f25aff3aa0318","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0xcea8ef6ce6235f2c2cdd13c9e8a3ed470725a638","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0xde5ff829fef54d1bdec957d9538a306f0ead1368","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0x2ce63497999f520cc2afaaadbcfc37afd9def4b0","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0xe722e6bce1a598e6b5d26e9975bf44140d2aa3e5","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0x4ef1e503c4f1e5664ac98294d0e42ddc9c0ff961","reverse":false},{"min_volume_usd":10000.0,"network":"base","pool":"0x2c206c7de24787f85b5c52d2ea339adc6d5af40f","reverse":false}]}'

[[trigger.oracle.data_feeds]]
id = "1000002"
data = '{"pair":{"base":"USR","quote":"USD"},"decimals":8,"category":"Crypto","market_hours":"Crypto","arguments":[{"min_volume_usd":500000.0,"network":"base","pool":"0xd3ee0a3b349237d68517df30bfb66be971f46ad9","reverse":false},{"min_volume_usd":500000.0,"network":"base","pool":"0xb924561a57fc60041414b8471cbc99d3497097fa","reverse":false},{"min_volume_usd":500000.0,"network":"base","pool":"0x97c9750305a39e06002edd851f3d37a862ac7060","reverse":false},{"min_volume_usd":500000.0,"network":"eth","pool":"0x3ee841f47947fefbe510366e4bbb49e145484195","reverse":false},{"min_volume_usd":500000.0,"network":"eth","pool":"0xc907ba505c2e1cbc4658c395d4a2c7e6d2c32656","reverse":false},{"min_volume_usd":500000.0,"network":"eth","pool":"0x8bb9cd887dd51c5aa8d7da9e244c94bec035e47c","reverse":false},{"min_volume_usd":500000.0,"network":"eth","pool":"0x8461537a9bfc5a1df57cf825f8a58049ef61557b","reverse":false},{"min_volume_usd":500000.0,"network":"eth","pool":"0x4628f13651ead6793f8d838b34b8f8522fb0cc52","reverse":true},{"min_volume_usd":500000.0,"network":"eth","pool":"0x38de22a3175708d45e7c7c64cd78479c8b56f76e","reverse":true},{"min_volume_usd":500000.0,"network":"eth","pool":"0xd552716f3bba4224a19d7eb37a31650d7ae10144","reverse":true}]}'
```

Took them from `.devenv/state/blocksense/reporter/a/spin.toml` after starting `process-compose`
created_at: 2025-04-10T14:22:49Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-11T09:08:19Z
body: ### 🚀 Deployment Links of Blocksense Network websites:

| Website | Latest Update | Commit |
|---------------------|----------|----------------------------------------------------------------------|
| 🌱 [Documentation](https://4ee3fb48.blocksense.pages.dev) | 11.04.2025 12:08:17 | 8f0eb3259de366eb6360b93a7ca0bf3614998dac |
| 📖 [UI Components](https://4e2bd968.blocksense-ui.pages.dev) | 11.04.2025 12:08:17 | 8f0eb3259de366eb6360b93a7ca0bf3614998dac |
| 🏴‍☠ [NFT website](https://319d583d.blocksense-nft.pages.dev) | 11.04.2025 12:08:17 | 8f0eb3259de366eb6360b93a7ca0bf3614998dac |
<!-- Sticky Pull Request Comment -->
author_association: NONE