Skip to content

Commit

Permalink
Merge branch 'main' into show-lp-section
Browse files Browse the repository at this point in the history
  • Loading branch information
sophialittlejohn authored Oct 16, 2024
2 parents 4a528f1 + 9f23153 commit 85040be
Show file tree
Hide file tree
Showing 13 changed files with 361 additions and 53 deletions.
6 changes: 3 additions & 3 deletions centrifuge-app/src/components/IssuerSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,13 @@ export function IssuerDetails({ metadata }: IssuerSectionProps) {
</Text>
</Box>
{metadata?.pool?.issuer?.categories?.length ? (
<Box width="50%" bg="white" padding={2} borderRadius={10} ml={1} height="min-content">
<Box width="50%" bg="white" padding={2} borderRadius={10} ml={1} height="min-content" alignSelf="center">
{metadata?.pool?.issuer?.categories.map((category) => (
<Box display="flex" justifyContent="space-between" padding={1}>
<Text color="textSecondary" variant="body2" style={{ minWidth: 120, textTransform: 'capitalize' }}>
<Text color="textSecondary" variant="body3" style={{ minWidth: 120, textTransform: 'capitalize' }}>
{formatCamelCase(category.customType) || formatCamelCase(category.type)}
</Text>
<Text variant="body2" style={{ fontWeight: 500 }}>
<Text variant="body3" style={{ fontWeight: 500 }}>
{category.type.includes('Rate') ? formatPercentage(category.value) : category.value}
</Text>
</Box>
Expand Down
48 changes: 31 additions & 17 deletions centrifuge-app/src/components/PoolCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ const StyledRouterTextLink = styled(RouterTextLink)`
const StyledCard = styled(Card)`
width: 100%;
max-width: 100%;
height: 300px;
height: 320px;
margin-right: 12px;
margin-bottom: 12px;
padding: 12px;
Expand Down Expand Up @@ -72,7 +71,8 @@ const tinlakeTranches = {
{ name: 'Senior', apr: '7%', minInvestment: '5K' },
],
shortDescription: ' Real estate bridge loans for fix and flip projects, maturing in 12-24 months.',
investorType: 'Qualified Investors',
investorType: 'Qualified US and non-US investors',
assetType: 'Residential real estate',
},
BT3: {
name: 'BlockTower Series 3',
Expand All @@ -82,6 +82,7 @@ const tinlakeTranches = {
],
shortDescription: ' Investment-grade consumer ABS, auto ABS, and CLOs under 4 years.',
investorType: 'Private',
assetType: 'Structured Credit',
},
BT4: {
name: 'BlockTower Series 4',
Expand All @@ -91,6 +92,7 @@ const tinlakeTranches = {
],
shortDescription: 'Investment-grade consumer ABS, auto ABS, and CLOs under 4 years.',
investorType: 'Private',
assetType: 'Structured Credit',
},
none: {
name: '-',
Expand All @@ -100,16 +102,18 @@ const tinlakeTranches = {
],
shortDescription: '',
investorType: '-',
assetType: '-',
},
}

export const DYF_POOL_ID = '1655476167'
export const NS3_POOL_ID = '1615768079'
export const NS2 = '0x53b2d22d07E069a3b132BfeaaD275b10273d381E'

export type CentrifugeTargetAPYs = keyof typeof centrifugeTargetAPYs
export const centrifugeTargetAPYs = {
[DYF_POOL_ID]: ['15%'],
[NS3_POOL_ID]: ['8.0%', '16%'],
[NS3_POOL_ID]: ['16%', '8%'],
}

type TinlakeTranchesKey = keyof typeof tinlakeTranches
Expand Down Expand Up @@ -148,19 +152,26 @@ export function PoolCard({
(key) => tinlakeTranches[key as TinlakeTranchesKey].name === name
) || 'none') as TinlakeTranchesKey

const renderText = (text: string, isApr?: boolean) => {
if (isApr && poolId === NS3_POOL_ID) {
const renderText = (text: string, isApr?: boolean, seniority?: number) => {
if (
(isApr && poolId === NS3_POOL_ID) ||
(isApr && poolId === DYF_POOL_ID) ||
(isApr && isTinlakePool && seniority === 0)
) {
return (
<Box display="flex">
<Box display="flex" alignItems="baseline">
<Text
fontWeight={500}
as="h2"
variant={isOneTranche ? 'heading1' : 'body1'}
style={{ width: 35, marginRight: 4 }}
style={{
width: isOneTranche ? 40 : 35,
marginRight: isOneTranche ? 12 : 4,
}}
>
{text}
</Text>
<Tooltips type="targetAPY" color="textSecondary" label="Target" size="xs" />
<Tooltips type="targetAPY" color="textSecondary" label="target" size="xs" />
</Box>
)
}
Expand Down Expand Up @@ -196,6 +207,7 @@ export function PoolCard({
).toDecimal()

return {
seniority: tranche.seniority,
name: trancheName,
apr: isTinlakePool
? tinlakeTranches[tinlakeKey].tranches.find((t) => t.name === trancheName)?.apr
Expand Down Expand Up @@ -263,32 +275,34 @@ export function PoolCard({
)}
<Stack>
<Text as="span" variant="body3" color="textButtonPrimaryDisabled">
{poolId === DYF_POOL_ID ? 'Target' : 'APY'}
APY
</Text>
{tranchesData?.map((tranche) => renderText(`${tranche.apr}`, true))}
{tranchesData?.map((tranche) => renderText(`${tranche.apr}`, true, tranche.seniority))}
</Stack>
<Stack>
<Text as="span" variant="body3" color="textButtonPrimaryDisabled">
<Text as="span" variant="body2" color="textButtonPrimaryDisabled">
Min. investment
</Text>
{tranchesData?.map((tranche) => renderText(`${tranche.minInvestment}`))}
</Stack>
</Box>
{(metaData?.pool?.issuer?.shortDescription || isTinlakePool) && (
<Box marginY={12}>
<Text as="p" variant="body3" color="textButtonPrimaryDisabled">
<Text as="p" variant="body2" color="textButtonPrimaryDisabled">
{isTinlakePool ? tinlakeTranches[tinlakeKey].shortDescription : metaData?.pool?.issuer?.shortDescription}
</Text>
</Box>
)}

<Box display="flex" justifyContent="space-between" mt={1}>
<Text variant="body3">Asset type</Text>
<StyledText variant="body3">{assetClass ?? '-'}</StyledText>
<Text variant="body2">Asset type</Text>
<StyledText variant="body2">
{isTinlakePool ? tinlakeTranches[tinlakeKey].assetType : assetClass ?? '-'}
</StyledText>
</Box>
<Box display="flex" justifyContent="space-between">
<Text variant="body3">Investor type</Text>
<StyledText variant="body3">
<Text variant="body2">Investor type</Text>
<StyledText variant="body2">
{isTinlakePool ? tinlakeTranches[tinlakeKey].investorType : metaData?.pool?.investorType ?? '-'}
</StyledText>
</Box>
Expand Down
6 changes: 3 additions & 3 deletions centrifuge-app/src/components/PoolList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export function PoolList() {
? Array(6)
.fill(true)
.map((_, index) => (
<Box as="li" key={index} width={isExtraLarge ? '25%' : isLarge ? '33%' : isMedium ? '48%' : '100%'}>
<Box as="li" key={index} width={isLarge ? '33%' : isMedium ? '48%' : '100%'}>
<PoolCard />
</Box>
))
Expand All @@ -96,7 +96,7 @@ export function PoolList() {
as="li"
key={pool.poolId}
status={pool.status}
width={isExtraLarge ? '25%' : isLarge ? '33%' : isMedium ? '48%' : '100%'}
width={isLarge ? '33%' : isMedium ? '48%' : '100%'}
>
<PoolCard {...pool} />
</PoolCardBox>
Expand Down Expand Up @@ -136,7 +136,7 @@ function ArchivedPools({ pools }: { pools: PoolCardProps[] }) {
as="li"
key={pool.poolId}
status={pool.status}
width={isExtraLarge ? '25%' : isLarge ? '33%' : isMedium ? '48%' : '100%'}
width={isLarge ? '33%' : isMedium ? '48%' : '100%'}
>
<PoolCard {...pool} />
</PoolCardBox>
Expand Down
32 changes: 25 additions & 7 deletions centrifuge-app/src/components/PoolOverview/KeyMetrics.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { CurrencyBalance, DailyTrancheState, Price } from '@centrifuge/centrifuge-js'
import { NetworkIcon, formatBalanceAbbreviated, useCentrifuge } from '@centrifuge/centrifuge-react'
import { Box, Card, IconArrowRightWhite, IconMoody, IconSp, Shelf, Stack, Text, Tooltip } from '@centrifuge/fabric'
import {
Box,
Card,
IconArrowRightWhite,
IconMoody,
IconParticula,
IconSp,
Shelf,
Stack,
Text,
Tooltip,
} from '@centrifuge/fabric'
import capitalize from 'lodash/capitalize'
import startCase from 'lodash/startCase'
import { useMemo } from 'react'
Expand Down Expand Up @@ -35,6 +46,11 @@ type Tranche = Pick<DailyTrancheState, 'id'> & {

type TinlakeDataKey = keyof typeof tinlakeData

const ratingIcons: { [key: string]: JSX.Element } = {
"Moody's": <IconMoody size={16} />,
Particula: <IconParticula size={16} />,
}

const tinlakeData = {
'0x53b2d22d07E069a3b132BfeaaD275b10273d381E': '7% - 15%',
'0x55d86d51Ac3bcAB7ab7d2124931FbA106c8b60c7': '4% - 15%',
Expand Down Expand Up @@ -124,7 +140,7 @@ export const KeyMetrics = ({ poolId }: Props) => {
value: tinlakeData[poolId as TinlakeDataKey]
? tinlakeData[poolId as TinlakeDataKey]
: centrifugeTargetAPYs[poolId as keyof typeof centrifugeTargetAPYs]
? centrifugeTargetAPYs[poolId as keyof typeof centrifugeTargetAPYs].join(' - ')
? centrifugeTargetAPYs[poolId as keyof typeof centrifugeTargetAPYs].reverse().join(' - ')
: tranchesAPY?.length
? tranchesAPY.map((tranche, index) => {
const formatted = formatPercentage(tranche)
Expand Down Expand Up @@ -176,17 +192,16 @@ export const KeyMetrics = ({ poolId }: Props) => {
<Shelf gap={1}>
{metadata?.pool?.poolRatings.map((rating) => (
<Tooltip
delay={300}
bodyWidth="maxContent"
body={
<TooltipBody
title={rating.agency ?? ''}
links={[
{ text: 'View report', url: rating.reportUrl ?? '' },
{ text: 'Go to report', url: rating.reportUrl ?? '' },
...(rating.reportFile
? [
{
text: 'Download report',
text: 'View PDF report',
url: cent.metadata.parseMetadataUrl(rating.reportFile?.uri ?? ''),
},
]
Expand All @@ -200,9 +215,12 @@ export const KeyMetrics = ({ poolId }: Props) => {
borderRadius={20}
padding="2px 10px"
display="flex"
alignItems="center"
width={80}
justifyContent="center"
>
{rating.agency?.includes('moody') ? <IconMoody size={16} /> : <IconSp size={16} />}
<Text>{rating.value}</Text>
{rating.agency && ratingIcons[rating.agency] ? ratingIcons[rating.agency] : <IconSp size={16} />}
<Text style={{ marginLeft: 4 }}>{rating.value}</Text>
</Box>
</Tooltip>
))}
Expand Down
25 changes: 16 additions & 9 deletions centrifuge-app/src/components/PoolOverview/TrancheTokenCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { usePool } from '../../utils/usePools'
import { DataTable } from '../DataTable'
import { CentrifugeTargetAPYs, DYF_POOL_ID, NS3_POOL_ID, centrifugeTargetAPYs } from '../PoolCard'
import { PoolMetaDataPartial } from '../PoolList'
import { Tooltips } from '../Tooltips'

type Row = {
tokenName: string
Expand All @@ -18,10 +19,9 @@ type Row = {
tokenPrice: Decimal
subordination: Decimal
trancheId: string
isTarget: boolean
}

const NS2 = '0x53b2d22d07E069a3b132BfeaaD275b10273d381E'

export const TrancheTokenCards = ({
trancheTokens,
poolId,
Expand All @@ -34,6 +34,7 @@ export const TrancheTokenCards = ({
const pool = usePool(poolId)
const theme = useTheme()
const isTinlakePool = poolId.startsWith('0x')
const daysSinceCreation = pool?.createdAt ? daysBetween(new Date(pool.createdAt), new Date()) : 0

const getTrancheText = (trancheToken: Token) => {
if (trancheToken.seniority === 0) return 'junior'
Expand All @@ -43,19 +44,21 @@ export const TrancheTokenCards = ({

const calculateApy = (trancheToken: Token) => {
if (isTinlakePool && getTrancheText(trancheToken) === 'senior') return formatPercentage(trancheToken.apy)
if (poolId === NS2 && trancheToken.seniority === 0) return '15%'
if (isTinlakePool && trancheToken.seniority === 0) return '15%'
if (poolId === DYF_POOL_ID) return centrifugeTargetAPYs[poolId as CentrifugeTargetAPYs][0]
if (poolId === NS3_POOL_ID && trancheToken.seniority === 0)
return centrifugeTargetAPYs[poolId as CentrifugeTargetAPYs][0]
if (poolId === NS3_POOL_ID && trancheToken.seniority === 1)
return centrifugeTargetAPYs[poolId as CentrifugeTargetAPYs][1]
const daysSinceCreation = pool?.createdAt ? daysBetween(new Date(pool.createdAt), new Date()) : 0
if (daysSinceCreation < 30) return 'N/A'
return trancheToken.yield30DaysAnnualized
? formatPercentage(new Perquintill(trancheToken.yield30DaysAnnualized))
: '-'
}

const getTarget = (tranche: Token) =>
(isTinlakePool && tranche.seniority === 0) || poolId === DYF_POOL_ID || poolId === NS3_POOL_ID

const columns = useMemo(() => {
return [
{
Expand All @@ -71,13 +74,16 @@ export const TrancheTokenCards = ({
},
},
{
header: poolId === DYF_POOL_ID || poolId === NS3_POOL_ID ? 'Target' : 'APY',
header: 'APY',
align: 'left',
cell: (row: Row) => {
return (
<Text paddingY={2} fontWeight="600" variant="heading2">
{row.apy}
</Text>
<Box>
<Text style={{ marginRight: 4 }} fontWeight="600" variant="heading2">
{row.apy}
</Text>
{row.isTarget && <Tooltips label="target" type="targetAPY" size="xs" />}
</Box>
)
},
},
Expand Down Expand Up @@ -137,9 +143,10 @@ export const TrancheTokenCards = ({
tokenPrice: tranche.tokenPrice,
subordination: tranche.protection,
trancheId: tranche.id,
isTarget: getTarget(tranche),
}
})
}, [trancheTokens])
}, [trancheTokens, getTarget])

Check warning on line 149 in centrifuge-app/src/components/PoolOverview/TrancheTokenCards.tsx

View workflow job for this annotation

GitHub Actions / build-app

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

Check warning on line 149 in centrifuge-app/src/components/PoolOverview/TrancheTokenCards.tsx

View workflow job for this annotation

GitHub Actions / ff-prod / build-app

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

return (
<Shelf gap={3}>
Expand Down
Loading

0 comments on commit 85040be

Please sign in to comment.