From 653adb292d403f40c520f7585420b00357046f45 Mon Sep 17 00:00:00 2001
From: zielvna <zielvna@gmail.com>
Date: Wed, 11 Sep 2024 18:10:56 +0200
Subject: [PATCH 1/3] use new api endpoint for stats

---
 src/store/consts/utils.ts |  47 +++++++++
 src/store/sagas/stats.ts  | 214 ++++----------------------------------
 2 files changed, 67 insertions(+), 194 deletions(-)

diff --git a/src/store/consts/utils.ts b/src/store/consts/utils.ts
index 2951b616..f443a2c6 100644
--- a/src/store/consts/utils.ts
+++ b/src/store/consts/utils.ts
@@ -693,6 +693,53 @@ export const getNetworkStats = async (name: string): Promise<Record<string, Pool
   return data
 }
 
+interface FullSnap {
+  volume24: {
+    value: number
+    change: number
+  }
+  tvl24: {
+    value: number
+    change: number
+  }
+  fees24: {
+    value: number
+    change: number
+  }
+  tokensData: TokenStatsDataWithString[]
+  poolsData: PoolStatsDataWithString[]
+  volumePlot: TimeData[]
+  liquidityPlot: TimeData[]
+}
+
+export interface TokenStatsDataWithString {
+  address: string
+  price: number
+  volume24: number
+  tvl: number
+}
+
+export interface TimeData {
+  timestamp: number
+  value: number
+}
+
+export interface PoolStatsDataWithString {
+  poolAddress: string
+  tokenX: string
+  tokenY: string
+  fee: number
+  volume24: number
+  tvl: number
+  apy: number
+}
+
+export const getFullSnap = async (name: string): Promise<FullSnap> => {
+  const { data } = await axios.get<FullSnap>(`http://localhost:3000/svm/full_snap/${name}`)
+
+  return data
+}
+
 export const getPoolsFromAdresses = async (
   addresses: PublicKey[],
   marketProgram: Market
diff --git a/src/store/sagas/stats.ts b/src/store/sagas/stats.ts
index 85acc5d0..6eeec0e6 100644
--- a/src/store/sagas/stats.ts
+++ b/src/store/sagas/stats.ts
@@ -1,213 +1,39 @@
-import { actions, PoolStatsData, TimeData, TokenStatsData } from '@reducers/stats'
-import { all, call, put, select, takeEvery } from 'typed-redux-saga'
-import { network, rpcAddress } from '@selectors/solanaConnection'
-import {
-  getJupPricesData,
-  getFullNewTokensData,
-  getNetworkStats,
-  getPoolsAPY,
-  getPoolsFromAdresses,
-  printBN
-} from '@consts/utils'
+import { actions } from '@reducers/stats'
+import { call, put, select, takeEvery } from 'typed-redux-saga'
+import { network } from '@selectors/solanaConnection'
+import { getFullNewTokensData, getFullSnap } from '@consts/utils'
 import { tokens } from '@selectors/pools'
 import { PublicKey } from '@solana/web3.js'
-import { getMarketProgram } from '@web3/programs/amm'
-import { PoolWithAddress, actions as poolsActions } from '@reducers/pools'
-import { DECIMAL } from '@invariant-labs/sdk/lib/utils'
+import { actions as poolsActions } from '@reducers/pools'
 import { getConnection } from './connection'
 
 export function* getStats(): Generator {
   try {
     const connection = yield* call(getConnection)
     const currentNetwork = yield* select(network)
-    const rpc = yield* select(rpcAddress)
-    const { data, poolsApy } = yield* all({
-      data: call(getNetworkStats, currentNetwork.toLowerCase()),
-      poolsApy: call(getPoolsAPY, currentNetwork.toLowerCase())
-    })
-
-    const marketProgram = yield* call(getMarketProgram, currentNetwork, rpc)
-
-    const allPoolsData = yield* call(
-      getPoolsFromAdresses,
-      Object.keys(data).map(addr => new PublicKey(addr)),
-      marketProgram
-    )
-    const poolsDataObject: Record<string, PoolWithAddress> = {}
-    allPoolsData.forEach(pool => {
-      poolsDataObject[pool.address.toString()] = pool
-    })
-
-    const volume24 = {
-      value: 0,
-      change: 0
-    }
-    const tvl24 = {
-      value: 0,
-      change: 0
-    }
-    const fees24 = {
-      value: 0,
-      change: 0
-    }
-
-    const tokensDataObject: Record<string, TokenStatsData> = {}
-    let poolsData: PoolStatsData[] = []
-
-    const volumeForTimestamps: Record<string, number> = {}
-    const liquidityForTimestamps: Record<string, number> = {}
-    const feesForTimestamps: Record<string, number> = {}
-
-    const lastTimestamp = Math.max(
-      ...Object.values(data)
-        .filter(snaps => snaps.length > 0)
-        .map(snaps => +snaps[snaps.length - 1].timestamp)
-    )
-
-    Object.entries(data).forEach(([address, snapshots]) => {
-      if (!poolsDataObject[address]) {
-        return
-      }
-
-      if (!tokensDataObject[poolsDataObject[address].tokenX.toString()]) {
-        tokensDataObject[poolsDataObject[address].tokenX.toString()] = {
-          address: poolsDataObject[address].tokenX,
-          price: 0,
-          volume24: 0,
-          tvl: 0
-        }
-      }
-
-      if (!tokensDataObject[poolsDataObject[address].tokenY.toString()]) {
-        tokensDataObject[poolsDataObject[address].tokenY.toString()] = {
-          address: poolsDataObject[address].tokenY,
-          price: 0,
-          volume24: 0,
-          tvl: 0
-        }
-      }
-
-      if (!snapshots.length) {
-        poolsData.push({
-          volume24: 0,
-          tvl: 0,
-          tokenX: poolsDataObject[address].tokenX,
-          tokenY: poolsDataObject[address].tokenY,
-          fee: +printBN(poolsDataObject[address].fee.v, DECIMAL - 2),
-          apy: poolsApy[address] ?? 0,
-          poolAddress: new PublicKey(address)
-        })
-        return
-      }
-
-      const tokenX = poolsDataObject[address].tokenX.toString()
-      const tokenY = poolsDataObject[address].tokenY.toString()
 
-      const lastSnapshot = snapshots[snapshots.length - 1]
-
-      tokensDataObject[tokenX].volume24 +=
-        lastSnapshot.timestamp === lastTimestamp ? lastSnapshot.volumeX.usdValue24 : 0
-      tokensDataObject[tokenY].volume24 +=
-        lastSnapshot.timestamp === lastTimestamp ? lastSnapshot.volumeY.usdValue24 : 0
-      tokensDataObject[tokenX].tvl += lastSnapshot.liquidityX.usdValue24
-      tokensDataObject[tokenY].tvl += lastSnapshot.liquidityY.usdValue24
-
-      poolsData.push({
-        volume24:
-          lastSnapshot.timestamp === lastTimestamp
-            ? lastSnapshot.volumeX.usdValue24 + lastSnapshot.volumeY.usdValue24
-            : 0,
-        tvl:
-          lastSnapshot.timestamp === lastTimestamp
-            ? lastSnapshot.liquidityX.usdValue24 + lastSnapshot.liquidityY.usdValue24
-            : 0,
-        tokenX: poolsDataObject[address].tokenX,
-        tokenY: poolsDataObject[address].tokenY,
-        fee: +printBN(poolsDataObject[address].fee.v, DECIMAL - 2),
-        apy: poolsApy[address] ?? 0,
-        poolAddress: new PublicKey(address)
-      })
-
-      snapshots.slice(-30).forEach(snapshot => {
-        const timestamp = snapshot.timestamp.toString()
-
-        if (!volumeForTimestamps[timestamp]) {
-          volumeForTimestamps[timestamp] = 0
-        }
-
-        if (!liquidityForTimestamps[timestamp]) {
-          liquidityForTimestamps[timestamp] = 0
-        }
-
-        if (!feesForTimestamps[timestamp]) {
-          feesForTimestamps[timestamp] = 0
-        }
-
-        volumeForTimestamps[timestamp] += snapshot.volumeX.usdValue24 + snapshot.volumeY.usdValue24
-        liquidityForTimestamps[timestamp] +=
-          snapshot.liquidityX.usdValue24 + snapshot.liquidityY.usdValue24
-        feesForTimestamps[timestamp] += snapshot.feeX.usdValue24 + snapshot.feeY.usdValue24
-      })
-    })
-
-    const tokensPricesData = yield* call(getJupPricesData, Object.keys(tokensDataObject))
-
-    Object.entries(tokensPricesData).forEach(([address, token]) => {
-      tokensDataObject[address].price = token.price
-    })
-
-    const volumePlot: TimeData[] = Object.entries(volumeForTimestamps)
-      .map(([timestamp, value]) => ({
-        timestamp: +timestamp,
-        value
-      }))
-      .sort((a, b) => a.timestamp - b.timestamp)
-    const liquidityPlot: TimeData[] = Object.entries(liquidityForTimestamps)
-      .map(([timestamp, value]) => ({
-        timestamp: +timestamp,
-        value
+    const fullSnap = yield* call(getFullSnap, currentNetwork.toLowerCase())
+    const parsedFullSnap = {
+      ...fullSnap,
+      tokensData: fullSnap.tokensData.map(token => ({
+        ...token,
+        address: new PublicKey(token.address)
+      })),
+      poolsData: fullSnap.poolsData.map(pool => ({
+        ...pool,
+        poolAddress: new PublicKey(pool.poolAddress),
+        tokenX: new PublicKey(pool.tokenX),
+        tokenY: new PublicKey(pool.tokenY)
       }))
-      .sort((a, b) => a.timestamp - b.timestamp)
-    const feePlot: TimeData[] = Object.entries(feesForTimestamps)
-      .map(([timestamp, value]) => ({
-        timestamp: +timestamp,
-        value
-      }))
-      .sort((a, b) => a.timestamp - b.timestamp)
-
-    const tiersToOmit = [0.001, 0.003]
-
-    poolsData = poolsData.filter(pool => !tiersToOmit.includes(pool.fee))
-
-    volume24.value = volumePlot.length ? volumePlot[volumePlot.length - 1].value : 0
-    tvl24.value = liquidityPlot.length ? liquidityPlot[liquidityPlot.length - 1].value : 0
-    fees24.value = feePlot.length ? feePlot[feePlot.length - 1].value : 0
-
-    const prevVolume24 = volumePlot.length > 1 ? volumePlot[volumePlot.length - 2].value : 0
-    const prevTvl24 = liquidityPlot.length > 1 ? liquidityPlot[liquidityPlot.length - 2].value : 0
-    const prevFees24 = feePlot.length > 1 ? feePlot[feePlot.length - 2].value : 0
-
-    volume24.change = ((volume24.value - prevVolume24) / prevVolume24) * 100
-    tvl24.change = ((tvl24.value - prevTvl24) / prevTvl24) * 100
-    fees24.change = ((fees24.value - prevFees24) / prevFees24) * 100
+    }
 
-    yield* put(
-      actions.setCurrentStats({
-        volume24,
-        tvl24,
-        fees24,
-        tokensData: Object.values(tokensDataObject),
-        poolsData,
-        volumePlot,
-        liquidityPlot
-      })
-    )
+    yield* put(actions.setCurrentStats(parsedFullSnap))
 
     const allTokens = yield* select(tokens)
 
     const unknownTokens = new Set<PublicKey>()
 
-    allPoolsData.forEach(pool => {
+    parsedFullSnap.poolsData.forEach(pool => {
       if (!allTokens[pool.tokenX.toString()]) {
         unknownTokens.add(pool.tokenX)
       }

From 3174c18335b8995b5d3e907b89967142897932bb Mon Sep 17 00:00:00 2001
From: zielvna <zielvna@gmail.com>
Date: Thu, 12 Sep 2024 15:21:32 +0200
Subject: [PATCH 2/3] replace localhost with invariant server

---
 src/store/consts/utils.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/store/consts/utils.ts b/src/store/consts/utils.ts
index f443a2c6..85ac6d11 100644
--- a/src/store/consts/utils.ts
+++ b/src/store/consts/utils.ts
@@ -735,7 +735,7 @@ export interface PoolStatsDataWithString {
 }
 
 export const getFullSnap = async (name: string): Promise<FullSnap> => {
-  const { data } = await axios.get<FullSnap>(`http://localhost:3000/svm/full_snap/${name}`)
+  const { data } = await axios.get<FullSnap>(`http://stats.invariant.app/svm/full_snap/${name}`)
 
   return data
 }

From d729e23f6a9ab928f497c20f0712aad364b1ef9d Mon Sep 17 00:00:00 2001
From: zielvna <zielvna@gmail.com>
Date: Thu, 12 Sep 2024 15:27:33 +0200
Subject: [PATCH 3/3] fix invariant stats address

---
 src/store/consts/utils.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/store/consts/utils.ts b/src/store/consts/utils.ts
index 85ac6d11..b6915faa 100644
--- a/src/store/consts/utils.ts
+++ b/src/store/consts/utils.ts
@@ -735,7 +735,7 @@ export interface PoolStatsDataWithString {
 }
 
 export const getFullSnap = async (name: string): Promise<FullSnap> => {
-  const { data } = await axios.get<FullSnap>(`http://stats.invariant.app/svm/full_snap/${name}`)
+  const { data } = await axios.get<FullSnap>(`https://stats.invariant.app/svm/full_snap/${name}`)
 
   return data
 }