diff --git a/centrifuge-app/src/pages/Pools.tsx b/centrifuge-app/src/pages/Pools.tsx
index c00410707..d1432ee86 100644
--- a/centrifuge-app/src/pages/Pools.tsx
+++ b/centrifuge-app/src/pages/Pools.tsx
@@ -1,7 +1,7 @@
import { formatBalance } from '@centrifuge/centrifuge-react'
-import { Box, IconArrowUpRight, Stack, StatusChip, Text } from '@centrifuge/fabric'
+import { Box, IconArrowDown, IconArrowUpRight, Stack, StatusChip, Text } from '@centrifuge/fabric'
import * as React from 'react'
-import { useListedPools } from '../../src/utils/useListedPools'
+import { getYearOverYearGrowth, useListedPools } from '../../src/utils/useListedPools'
import { LayoutSection } from '../components/LayoutBase/LayoutSection'
import { PoolList } from '../components/PoolList'
import { prefetchRoute } from '../components/Root'
@@ -10,6 +10,9 @@ import { Dec } from '../utils/Decimal'
export default function PoolsPage() {
const [, listedTokens] = useListedPools()
+ const { totalValueLockedGrowth, isLoading } = getYearOverYearGrowth()
+ const isPositiveYoy = totalValueLockedGrowth > 0
+ const IconComponent = isPositiveYoy ? IconArrowUpRight : IconArrowDown
const totalValueLocked = React.useMemo(() => {
return (
@@ -41,12 +44,16 @@ export default function PoolsPage() {
Total value locked (TVL)
-
-
-
- 24% YoY
-
-
+ {!isLoading && (
+
+
+
+
+ {formatBalance(totalValueLockedGrowth ?? 0, '', 2)} YoY
+
+
+
+ )}
{formatBalance(totalValueLocked ?? 0, config.baseCurrency)}
diff --git a/centrifuge-app/src/utils/useListedPools.ts b/centrifuge-app/src/utils/useListedPools.ts
index 7f03ea92d..6645f512e 100644
--- a/centrifuge-app/src/utils/useListedPools.ts
+++ b/centrifuge-app/src/utils/useListedPools.ts
@@ -1,12 +1,20 @@
-import { PoolMetadata } from '@centrifuge/centrifuge-js'
+import { CurrencyBalance, PoolMetadata } from '@centrifuge/centrifuge-js'
import BN from 'bn.js'
import * as React from 'react'
+import { useMemo } from 'react'
import { useAddress } from '../utils/useAddress'
import { useMetadataMulti } from '../utils/useMetadata'
import { usePermissions } from '../utils/usePermissions'
import { usePools } from '../utils/usePools'
+import { Dec } from './Decimal'
import { getPoolTVL } from './getPoolTVL'
import { useTinlakePools } from './tinlake/useTinlakePools'
+import { useSubquery } from './useSubquery'
+
+type FlattenedDataItem = {
+ netAssetValue: string
+ decimals: number
+}
const sign = (n: BN) => (n.isZero() ? 0 : n.isNeg() ? -1 : 1)
@@ -40,3 +48,84 @@ export function useListedPools() {
return [listedPools, listedTokens, isLoading] as const
}
+
+export function getYearOverYearGrowth() {
+ const [listedPools] = useListedPools()
+
+ const { oneDayAgoFromOneYearAgo, nextDay } = useMemo(() => {
+ const today = new Date()
+ const oneYearAgo = new Date(Date.UTC(today.getUTCFullYear() - 1, today.getUTCMonth(), today.getUTCDate(), 0, 0, 0))
+
+ const addOneDay = (date: Date): Date => {
+ const newDate = new Date(date)
+ newDate.setDate(date.getDate() + 1)
+ return newDate
+ }
+
+ return {
+ oneDayAgoFromOneYearAgo: oneYearAgo,
+ nextDay: addOneDay(oneYearAgo),
+ }
+ }, [])
+
+ const { data, isLoading } = useSubquery(
+ `query ($oneDayAgoFromOneYearAgo: Datetime!, $nextDay: Datetime!) {
+ pools {
+ nodes {
+ currency {
+ decimals
+ }
+ poolSnapshots(
+ filter: {
+ timestamp: {
+ greaterThan: $oneDayAgoFromOneYearAgo,
+ lessThan: $nextDay
+ }
+ },
+ ) {
+ nodes {
+ netAssetValue
+ timestamp
+ }
+ }
+ }
+ }
+ }`,
+ {
+ oneDayAgoFromOneYearAgo,
+ nextDay,
+ },
+ {
+ enabled: !!oneDayAgoFromOneYearAgo,
+ }
+ )
+
+ const flattenedData =
+ data?.pools?.nodes.flatMap((pool: any) =>
+ pool.poolSnapshots.nodes.map((snapshot: any) => ({
+ netAssetValue: snapshot.netAssetValue,
+ decimals: pool.currency.decimals,
+ }))
+ ) || []
+
+ // Aggregate NAV from last year
+ const aggregatedNetAssetValue = flattenedData.reduce((accumulator: any, item: FlattenedDataItem) => {
+ const netAssetValue = new CurrencyBalance(item.netAssetValue, item.decimals)
+ return accumulator.add(netAssetValue.toDecimal())
+ }, Dec(0))
+
+ const aggregatedListedPoolsNav = listedPools.reduce((accumulator, pool) => {
+ const decimal = pool.currency?.decimals ?? 0
+ const navTotal = new CurrencyBalance(pool.nav.total, decimal)
+ return accumulator.add(navTotal.toDecimal())
+ }, Dec(0))
+
+ const lastYearNAV = aggregatedNetAssetValue.toNumber()
+ const currentYearNAV = aggregatedListedPoolsNav.toNumber()
+
+ // YoY growth
+ const totalValueLockedGrowth =
+ lastYearNAV && currentYearNAV ? ((currentYearNAV - lastYearNAV) / lastYearNAV) * 100 : 0
+
+ return { totalValueLockedGrowth, isLoading }
+}