synapsecns/sanguine

View on GitHub
packages/synapse-interface/slices/poolDataSlice.ts

Summary

Maintainability
A
3 hrs
Test Coverage
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { Token } from '@types'

import { POOL_BY_ROUTER_INDEX } from '@/constants/tokens'
import { getPoolTokenInfoArr, getTokenBalanceInfo } from '@/utils/poolDataFuncs'
import { getPoolApyData } from '@/utils/actions/getPoolApyData'
import { getBalanceData } from '@/utils/actions/getPoolData'
import { getCorePoolData } from '@/utils/actions/getCorePoolData'
import { getAvaxPrice, getEthPrice } from '@/utils/actions/getPrices'

export interface PoolDataState {
  pool: Token | undefined
  // poolData: {
  //   name: string
  //   tokens: Token[]
  //   totalLocked: number
  //   totalLockedUSD: number
  //   virtualPrice: string
  //   swapFee: string
  // }
  poolData: any
  poolAPYData: any
  isLoading: boolean
}

const initialState: PoolDataState = {
  pool: undefined,
  poolData: {
    name: undefined,
    tokens: undefined,
    totalLocked: undefined,
    totalLockedUSD: undefined,
    virtualPrice: undefined,
    swapFee: undefined,
  },
  poolAPYData: {
    fullCompoundedApyStr: undefined,
    weeklyAPR: undefined,
    yearlyAPRUnvested: undefined,
  },
  isLoading: true,
}

export const fetchPoolData = createAsyncThunk(
  'poolData/fetch',
  async ({ poolName }: { poolName: string }) => {
    const pool = POOL_BY_ROUTER_INDEX[poolName]
    const chainId = pool.chainId

    const poolAddress = pool?.swapAddresses[chainId]

    if (!pool || !poolAddress) {
      return null
    }

    const lpTokenAddress = pool?.addresses[chainId]

    const { tokenBalances } = await getBalanceData({
      pool,
      chainId,
      address: poolAddress,
      lpTokenAddress,
    })

    const { swapFee, virtualPrice } = await getCorePoolData(
      poolAddress,
      chainId
    )

    const ethPrice = await getEthPrice()
    const avaxPrice = await getAvaxPrice()

    const {
      tokenBalancesSum,
      tokenBalancesUSD,
    }: { tokenBalancesSum: number; tokenBalancesUSD: number } =
      getTokenBalanceInfo({
        tokenBalances: tokenBalances
          .filter((t) => !t.isLP)
          .map((t) => t.balance),
        prices: {
          ethPrice,
          avaxPrice,
        },
        poolType: pool?.poolType,
      })

    const poolTokensMatured = getPoolTokenInfoArr({
      tokenBalances: tokenBalances.filter((t) => !t.isLP),
      tokenBalancesSum,
    })

    const poolAPYData = await getPoolApyData(chainId, pool)

    // prob should split into multiple thunks to handle loading
    // separately
    return {
      pool,
      poolAPYData,
      poolData: {
        name: pool.name,
        tokens: poolTokensMatured,
        totalLocked: tokenBalancesSum,
        totalLockedUSD: tokenBalancesUSD,
        virtualPrice,
        swapFee,
      },
    }
  }
)

export const poolDataSlice = createSlice({
  name: 'poolData',
  initialState,
  reducers: {
    resetPoolData: () => initialState,
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchPoolData.pending, (state) => {
        state.isLoading = true
      })
      .addCase(fetchPoolData.fulfilled, (state, action) => {
        state.isLoading = false
        state.pool = action.payload.pool
        state.poolData = action.payload.poolData
        state.poolAPYData = action.payload.poolAPYData
      })
      .addCase(fetchPoolData.rejected, (state) => {
        state.isLoading = false
      })
  },
})

export const { resetPoolData } = poolDataSlice.actions
export const selectPool = (state) => state.poolData.pool

export default poolDataSlice.reducer