synapsecns/sanguine

View on GitHub
packages/synapse-interface/utils/actions/getPoolData.ts

Summary

Maintainability
B
6 hrs
Test Coverage
import { multicall } from '@wagmi/core'
import { erc20Abi } from 'viem'
import { Token, PoolData } from '@types'
import { formatBigIntToString } from '@utils/bigint/format'
import { getPoolTokenInfoArr, getTokenBalanceInfo } from '@utils/poolDataFuncs'
import { getEthPrice, getAvaxPrice } from '@utils/actions/getPrices'

import lpTokenABI from '@/constants/abis/lpToken.json'
import { SWAP_ABI } from '@/constants/abis/swap'
import { wagmiConfig } from '@/wagmiConfig'

export const getBalanceData = async ({
  pool,
  chainId,
  address,
  lpTokenAddress,
}: {
  pool: Token
  chainId: number
  address: string
  lpTokenAddress: string
}) => {
  const tokens: Token[] = [...pool?.poolTokens, pool]
  const tokenBalances = []
  let poolTokenSum = 0n
  let lpTokenBalance = 1n

  const multicallInputs = []

  const one = {
    address: lpTokenAddress,
    abi: lpTokenABI,
    functionName: 'totalSupply',
    chainId,
  }

  multicallInputs.push(one)

  tokens?.forEach((token, index) => {
    const isLP = token.addresses[chainId] === lpTokenAddress
    // Use pool's getTokenBalance for pool tokens, if the address is the pool itself
    // to exclude the unclaimed admin fees
    if (address === pool.swapAddresses[chainId] && !isLP) {
      multicallInputs.push({
        address: pool.swapAddresses[chainId],
        abi: SWAP_ABI,
        functionName: 'getTokenBalance',
        chainId,
        args: [index],
      })
    } else {
      multicallInputs.push({
        address: token.addresses[chainId],
        abi: erc20Abi,
        functionName: 'balanceOf',
        chainId,
        args: [address],
      })
    }
  })
  const two = {
    address: pool.swapAddresses[chainId],
    abi: SWAP_ABI,
    functionName: 'swapStorage',
    chainId,
  }

  const three = {
    address: pool.swapAddresses[chainId],
    abi: SWAP_ABI,
    functionName: 'getVirtualPrice',
    chainId,
  }

  multicallInputs.push(two)
  multicallInputs.push(three)

  // @ts-ignore
  const multicallData: any[] = await multicall(wagmiConfig, {
    contracts: multicallInputs,
    chainId,
  }).catch((error) => {
    console.error('Multicall failed:', error)
    return []
  })

  const lpTotalSupply = multicallData[0].result ?? 0n

  tokens.forEach((token, index) => {
    const isLP = token.addresses[chainId] === lpTokenAddress

    tokenBalances.push({
      rawBalance: multicallData[index + 1].result ?? 0n,
      balance: formatBigIntToString(
        multicallData[index + 1].result,
        token.decimals[chainId]
      ),
      token,
      isLP,
    })

    if (isLP) {
      lpTokenBalance = multicallData[index + 1].result
    }

    poolTokenSum = poolTokenSum + multicallData[index + 1].result
  })

  return {
    tokenBalances,
    poolTokenSum,
    lpTokenBalance,
    lpTotalSupply,
  }
}

export const getSinglePoolData = async (
  chainId: number,
  pool: Token,
  prices?: any
): Promise<PoolData> => {
  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 ethPrice = prices?.ethPrice ?? (await getEthPrice())
  const avaxPrice = prices?.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,
  })

  return {
    name: pool.name,
    tokens: poolTokensMatured,
    totalLocked: tokenBalancesSum,
    totalLockedUSD: tokenBalancesUSD,
  }
}