Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix token price chart #1882

Merged
merged 8 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion centrifuge-app/src/components/Charts/CashDragChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type ChartData = {
export default function CashDragChart() {
const theme = useTheme()
const { pid: poolId } = useParams<{ pid: string }>()
const poolStates = useDailyPoolStates(poolId)
const { poolStates } = useDailyPoolStates(poolId) || {}
const pool = usePool(poolId)

if (!poolStates || poolStates?.length < 1) return <Text variant="body2">No data available</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ type ChartData = {
reserve: [number, number]
}

const PoolAssetReserveChart: React.VFC = () => {
function PoolAssetReserveChart() {
const theme = useTheme()
const { pid: poolId } = useParams<{ pid: string }>()
const poolStates = useDailyPoolStates(poolId)
const { poolStates } = useDailyPoolStates(poolId) || {}
const pool = usePool(poolId)
const poolAge = pool.createdAt ? daysBetween(pool.createdAt, new Date()) : 0

Expand Down Expand Up @@ -93,10 +93,7 @@ const PoolAssetReserveChart: React.VFC = () => {
)
}

const CustomLegend: React.VFC<{
currency: string
data: ChartData
}> = ({ data, currency }) => {
function CustomLegend({ data, currency }: { currency: string; data: ChartData }) {
const theme = useTheme()

return (
Expand Down
16 changes: 11 additions & 5 deletions centrifuge-app/src/components/Charts/PriceYieldChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useParams } from 'react-router'
import { CartesianGrid, ComposedChart, Line, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'
import { useTheme } from 'styled-components'
import { formatBalance } from '../../utils/formatting'
import { useDailyTrancheStates, usePool } from '../../utils/usePools'
import { useDailyPoolStates, usePool } from '../../utils/usePools'
import { Spinner } from '../Spinner'
import { CustomizedTooltip } from './Tooltip'

Expand All @@ -13,14 +13,20 @@ type ChartData = {
tokenPrice: number
}

const PriceYieldChart: React.FC<{
function PriceYieldChart({
trancheId,
onDataLoaded = () => {},
renderFallback = true,
}: {
trancheId: string
poolId: string
onDataLoaded?: (b: boolean) => void
renderFallback?: boolean
}> = ({ trancheId, onDataLoaded = () => {}, renderFallback = true }) => {
}) {
const theme = useTheme()
const { pid: poolId } = useParams<{ pid: string }>()
const trancheStates = useDailyTrancheStates(trancheId)
const { trancheStates: tranches } = useDailyPoolStates(poolId, undefined, undefined, false) || {}
const trancheStates = tranches?.[trancheId]
const pool = usePool(poolId)

const data: ChartData[] = React.useMemo(() => {
Expand All @@ -38,7 +44,7 @@ const PriceYieldChart: React.FC<{
onDataLoaded(data.length > 0)
}, [data, onDataLoaded])

if (!trancheStates || trancheStates?.length === 1) return <Spinner />
if (!tranches && !poolId.startsWith('0x')) return <Spinner />

return data && data.length > 0 ? (
<Stack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
}: LiquidityTransactionsSectionProps) {
const to = new Date(pool.epoch.lastClosed)
const from = pool.createdAt ? new Date(pool.createdAt) : new Date(to.getDate() - 10)
const dailyPoolStates = useDailyPoolStates(pool.id, from, to)
const { poolStates: dailyPoolStates } = useDailyPoolStates(pool.id, from, to) || {}

const dataUrl: any = React.useMemo(() => {
if (!dailyPoolStates || !dailyPoolStates?.length) {
Expand All @@ -60,7 +60,7 @@
}))

return getCSVDownloadUrl(formatted)
}, [dailyPoolStates, dataKeys, dataNames, pool.currency.symbol])

Check warning on line 63 in centrifuge-app/src/components/LiquidityTransactionsSection.tsx

View workflow job for this annotation

GitHub Actions / build-app

React Hook React.useMemo has a missing dependency: 'pool.currency.decimals'. Either include it or remove the dependency array

const chartData: StackedBarChartProps['data'] = React.useMemo(() => {
return (
Expand All @@ -82,7 +82,7 @@
}
}) || []
)
}, [dailyPoolStates, dataKeys])

Check warning on line 85 in centrifuge-app/src/components/LiquidityTransactionsSection.tsx

View workflow job for this annotation

GitHub Actions / build-app

React Hook React.useMemo has a missing dependency: 'pool.currency.decimals'. Either include it or remove the dependency array

const legend: LegendProps['data'] = React.useMemo(() => {
const topTotal = chartData.map(({ top }) => top).reduce((a, b) => a + b, 0)
Expand Down
9 changes: 7 additions & 2 deletions centrifuge-app/src/components/PoolToken.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Spinner } from './Spinner'
const PriceYieldChart = React.lazy(() => import('./Charts/PriceYieldChart'))

type PoolTokenProps = {
token: any
token: { id: string; poolId: string; name: string; symbol: string }
defaultOpen: boolean
children: React.ReactNode
}
Expand All @@ -29,7 +29,12 @@ export function PoolToken({ token, defaultOpen, children }: PoolTokenProps) {
>
<Stack maxHeight="300px">
<React.Suspense fallback={<Spinner />}>
<PriceYieldChart trancheId={token.id} onDataLoaded={setShowChart} renderFallback={false} />
<PriceYieldChart
trancheId={token.id}
poolId={token.poolId}
onDataLoaded={setShowChart}
renderFallback={false}
/>
</React.Suspense>
</Stack>
</InteractiveCard>
Expand Down
2 changes: 1 addition & 1 deletion centrifuge-app/src/components/Report/PoolBalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { UserFeedback } from './UserFeedback'
export function PoolBalance({ pool }: { pool: Pool }) {
const { startDate, endDate, groupBy, setCsvData } = React.useContext(ReportContext)

const dailyPoolStates = useDailyPoolStates(pool.id, startDate, endDate)
const { poolStates: dailyPoolStates } = useDailyPoolStates(pool.id, startDate, endDate) || {}
const monthlyPoolStates = useMonthlyPoolStates(pool.id, startDate, endDate)
const poolStates = groupBy === 'day' ? dailyPoolStates : monthlyPoolStates

Expand Down
4 changes: 3 additions & 1 deletion centrifuge-app/src/pages/Pool/Overview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { PoolToken } from '../../../components/PoolToken'
import { Spinner } from '../../../components/Spinner'
import { Tooltips } from '../../../components/Tooltips'
import { TrancheTokenCards } from '../../../components/TrancheTokenCards'
import { formatDate } from '../../../utils/date'
import { Dec } from '../../../utils/Decimal'
import { formatDate } from '../../../utils/date'
import { formatBalance, formatBalanceAbbreviated, formatPercentage } from '../../../utils/formatting'
import { getPoolValueLocked } from '../../../utils/getPoolValueLocked'
import { useTinlakePermissions } from '../../../utils/tinlake/useTinlakePermissions'
Expand All @@ -29,6 +29,7 @@ import { PoolDetailHeader } from '../Header'
const PoolAssetReserveChart = React.lazy(() => import('../../../components/Charts/PoolAssetReserveChart'))

export type Token = {
poolId: string
apy: Decimal
protection: Decimal
ratio: number
Expand Down Expand Up @@ -85,6 +86,7 @@ export function PoolDetailOverview() {
.map((tranche) => {
const protection = tranche.minRiskBuffer?.toDecimal() ?? Dec(0)
return {
poolId: tranche.poolId,
apy: tranche?.interestRatePerSec ? tranche?.interestRatePerSec.toAprPercent() : Dec(0),
protection: protection.mul(100),
ratio: tranche.ratio.toFloat(),
Expand Down
18 changes: 3 additions & 15 deletions centrifuge-app/src/utils/usePools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,25 +129,13 @@ export function useBorrowerAssetTransactions(poolId: string, assetId: string, fr
return result
}

export function useDailyPoolStates(poolId: string, from?: Date, to?: Date) {
if (poolId.startsWith('0x')) throw new Error('Only works with Centrifuge Pools')
export function useDailyPoolStates(poolId: string, from?: Date, to?: Date, suspense = true) {
const [result] = useCentrifugeQuery(
['dailyPoolStates', poolId, from, to],
(cent) => cent.pools.getDailyPoolStates([poolId, from, to]),
{
suspense: true,
}
)

return result
}

export function useDailyTrancheStates(trancheId: string) {
const [result] = useCentrifugeQuery(
['dailyTrancheStates', { trancheId }],
(cent) => cent.pools.getDailyTrancheStates([trancheId]),
{
suspense: true,
suspense,
enabled: !poolId.startsWith('0x'),
}
)

Expand Down
115 changes: 63 additions & 52 deletions centrifuge-js/src/modules/pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -556,14 +556,13 @@ export type DailyPoolState = {
totalReserve: CurrencyBalance
}
poolValue: CurrencyBalance
currency: string
timestamp: string
tranches: { [trancheId: string]: DailyTrancheState }

sumBorrowedAmountByPeriod: number | null
sumRepaidAmountByPeriod: number | null
sumInvestedAmountByPeriod: number | null
sumRedeemedAmountByPeriod: number | null
sumBorrowedAmountByPeriod?: number | null
sumRepaidAmountByPeriod?: number | null
sumInvestedAmountByPeriod?: number | null
sumRedeemedAmountByPeriod?: number | null
blockNumber: number
}

Expand Down Expand Up @@ -2180,50 +2179,62 @@ export function getPoolsModule(inst: Centrifuge) {
),
getPoolCurrency([poolId]),
]).pipe(
switchMap(([{ poolSnapshots }, { trancheSnapshots }, poolCurrency]) => {
return [
poolSnapshots?.map((state) => {
const poolState = {
id: state.id,
portfolioValuation: new CurrencyBalance(state.portfolioValuation, poolCurrency.decimals),
totalReserve: new CurrencyBalance(state.totalReserve, poolCurrency.decimals),
}
const poolValue = new CurrencyBalance(
new BN(state?.portfolioValuation || '0').add(new BN(state?.totalReserve || '0')),
poolCurrency.decimals
)

// TODO: This is inefficient, would be better to construct a map indexed by the timestamp
const trancheSnapshotsToday = trancheSnapshots?.filter((t) => t.timestamp === state.timestamp)

const tranches: { [trancheId: string]: DailyTrancheState } = {}
trancheSnapshotsToday?.forEach((tranche) => {
const tid = tranche.trancheId.split('-')[1]
tranches[tid] = {
id: tranche.trancheId,
price: tranche.tokenPrice ? new Price(tranche.tokenPrice) : null,
fulfilledInvestOrders: new CurrencyBalance(
tranche.sumFulfilledInvestOrdersByPeriod,
poolCurrency.decimals
),
fulfilledRedeemOrders: new CurrencyBalance(
tranche.sumFulfilledRedeemOrdersByPeriod,
poolCurrency.decimals
),
outstandingInvestOrders: new CurrencyBalance(
tranche.sumOutstandingInvestOrdersByPeriod,
poolCurrency.decimals
),
outstandingRedeemOrders: new CurrencyBalance(
tranche.sumOutstandingRedeemOrdersByPeriod,
poolCurrency.decimals
),
map(([{ poolSnapshots }, { trancheSnapshots }, poolCurrency]) => {
const trancheStates: Record<string, { timestamp: string; tokenPrice: Price }[]> = {}
trancheSnapshots?.forEach((state) => {
const tid = state.trancheId.split('-')[1]
const entry = { timestamp: state.timestamp, tokenPrice: new Price(state.tokenPrice) }
if (trancheStates[tid]) {
trancheStates[tid].push(entry)
} else {
trancheStates[tid] = [entry]
}
})
return {
poolStates:
poolSnapshots?.map((state) => {
const poolState = {
id: state.id,
portfolioValuation: new CurrencyBalance(state.portfolioValuation, poolCurrency.decimals),
totalReserve: new CurrencyBalance(state.totalReserve, poolCurrency.decimals),
}
})
const poolValue = new CurrencyBalance(
new BN(state?.portfolioValuation || '0').add(new BN(state?.totalReserve || '0')),
poolCurrency.decimals
)

return { ...state, poolState, poolValue, tranches }
}) as unknown as DailyPoolState[],
]
// TODO: This is inefficient, would be better to construct a map indexed by the timestamp
const trancheSnapshotsToday = trancheSnapshots?.filter((t) => t.timestamp === state.timestamp)

const tranches: { [trancheId: string]: DailyTrancheState } = {}
trancheSnapshotsToday?.forEach((tranche) => {
const tid = tranche.trancheId.split('-')[1]
tranches[tid] = {
id: tranche.trancheId,
price: tranche.tokenPrice ? new Price(tranche.tokenPrice) : null,
fulfilledInvestOrders: new CurrencyBalance(
tranche.sumFulfilledInvestOrdersByPeriod,
poolCurrency.decimals
),
fulfilledRedeemOrders: new CurrencyBalance(
tranche.sumFulfilledRedeemOrdersByPeriod,
poolCurrency.decimals
),
outstandingInvestOrders: new CurrencyBalance(
tranche.sumOutstandingInvestOrdersByPeriod,
poolCurrency.decimals
),
outstandingRedeemOrders: new CurrencyBalance(
tranche.sumOutstandingRedeemOrdersByPeriod,
poolCurrency.decimals
),
}
})

return { ...state, poolState, poolValue, tranches }
}) || [],
trancheStates,
}
})
)
}
Expand Down Expand Up @@ -2294,7 +2305,7 @@ export function getPoolsModule(inst: Centrifuge) {
const $query = inst.getSubqueryObservable<{ trancheSnapshots: { nodes: SubqueryTrancheSnapshot[] } }>(
`query($trancheId: String!) {
trancheSnapshots(
orderBy: BLOCK_NUMBER_ASC,
orderBy: BLOCK_NUMBER_DESC,
filter: {
trancheId: { includes: $trancheId },
}) {
Expand All @@ -2320,7 +2331,7 @@ export function getPoolsModule(inst: Centrifuge) {
if (!data) {
return []
}
return data.trancheSnapshots.nodes.map((state) => {
return data.trancheSnapshots.nodes.reverse().map((state) => {
return {
...state,
tokenPrice: new Price(state.tokenPrice),
Expand All @@ -2332,15 +2343,15 @@ export function getPoolsModule(inst: Centrifuge) {

function getMonthlyPoolStates(args: [poolId: string, from?: Date, to?: Date]) {
return getDailyPoolStates(args).pipe(
map((poolStates) => {
if (!poolStates) return []
map(({ poolStates }) => {
if (!poolStates.length) return []
// group by month
// todo: find last of each month
const poolStatesByMonth: { [monthYear: string]: DailyPoolState[] } = {}
poolStates.forEach((poolState) => {
const monthYear = `${new Date(poolState.timestamp).getMonth()}-${new Date(poolState.timestamp).getFullYear()}`
if (monthYear in poolStatesByMonth) {
poolStatesByMonth[monthYear] = [...poolStatesByMonth[monthYear], poolState]
poolStatesByMonth[monthYear].push(poolState)
} else {
poolStatesByMonth[monthYear] = [poolState]
}
Expand Down
1 change: 0 additions & 1 deletion fabric/src/components/TextInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export type TextInputProps = React.InputHTMLAttributes<HTMLInputElement> &
InputUnitProps & {
action?: React.ReactNode
symbol?: React.ReactNode
rightElement?: React.ReactNode
}
export type TextAreaInputProps = React.InputHTMLAttributes<HTMLTextAreaElement> &
InputUnitProps & {
Expand Down
Loading