Skip to content
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
17 changes: 16 additions & 1 deletion src/components/CCIP/Chain/Chain.astro
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import ChainHero from "~/components/CCIP/ChainHero/ChainHero"
import ChainTable from "~/components/CCIP/Tables/ChainTable"
import { getTokenIconUrl } from "~/features/utils"
import ChainTokenGrid from "./ChainTokenGrid"
import { fetchAllPoolData } from "~/lib/ccip/graphql/services/enrichment-data-service.ts"
import { generateChainStructuredData } from "~/utils/ccipStructuredData"
import StructuredData from "~/components/StructuredData.astro"
import { DOCS_BASE_URL } from "~/utils/structuredData"
Expand Down Expand Up @@ -50,6 +51,14 @@ const lanes = await getAllNetworkLanes({

const searchLanes = getSearchLanes({ environment })

const allPoolData = await fetchAllPoolData(environment)
const poolDataByToken: Record<string, { address: string; rawType: string; type: string; version: string }> = {}
for (const [tokenId, chainPoolData] of Object.entries(allPoolData)) {
if (chainPoolData[network.chain]) {
poolDataByToken[tokenId] = chainPoolData[network.chain]
}
}

const allVerifiers = getAllUniqueVerifiers({
environment,
version: Version.V1_2_0,
Expand Down Expand Up @@ -144,7 +153,13 @@ const chainStructuredData = generateChainStructuredData(
)
}
</div>
<ChainTokenGrid tokens={allTokens} network={network} client:only="react" environment={environment} />
<ChainTokenGrid
tokens={allTokens}
network={network}
client:only="react"
environment={environment}
poolDataByToken={poolDataByToken}
/>
</div>
</section>
</CcipDirectoryLayout>
Expand Down
14 changes: 9 additions & 5 deletions src/components/CCIP/Chain/ChainTokenGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Environment, Version, Network } from "~/config/data/ccip/types.ts"
import type { PoolType } from "~/config/data/ccip/types.ts"
import { getTokenData } from "~/config/data/ccip/data.ts"
import TokenCard from "../Cards/TokenCard.tsx"
import { drawerContentStore, DrawerWidth, drawerWidthStore } from "../Drawer/drawerStore.ts"
Expand All @@ -7,6 +8,7 @@ import { directoryToSupportedChain, getChainIcon, getChainTypeAndFamily, getTitl
import { useState } from "react"
import "./ChainTokenGrid.css"
import SeeMore from "../SeeMore/SeeMore.tsx"
import type { PoolInfo } from "~/lib/ccip/graphql/services/enrichment-data-service.ts"

interface ChainTokenGridProps {
tokens: {
Expand All @@ -16,11 +18,12 @@ interface ChainTokenGridProps {
}[]
network: Network
environment: Environment
poolDataByToken?: Record<string, PoolInfo>
}

const BEFORE_SEE_MORE = 6 * 4 // Number of networks to show before the "See more" button, 7 rows x 4 items

function ChainTokenGrid({ tokens, network, environment }: ChainTokenGridProps) {
function ChainTokenGrid({ tokens, network, environment, poolDataByToken }: ChainTokenGridProps) {
const [seeMore, setSeeMore] = useState(tokens.length <= BEFORE_SEE_MORE)
return (
<>
Expand All @@ -38,6 +41,7 @@ function ChainTokenGrid({ tokens, network, environment }: ChainTokenGridProps) {
key={token.id}
variant="square"
onClick={() => {
const poolInfo = poolDataByToken?.[token.id]
const selectedNetwork = Object.keys(data)
.map((key) => {
const supportedChain = directoryToSupportedChain(key || "")
Expand All @@ -54,10 +58,10 @@ function ChainTokenGrid({ tokens, network, environment }: ChainTokenGridProps) {
tokenSymbol: data[key].symbol,
tokenDecimals: data[key].decimals,
tokenAddress: data[key].tokenAddress,
tokenPoolType: data[key].pool?.type ?? "burnMint",
tokenPoolRawType: data[key].pool?.rawType ?? "",
tokenPoolAddress: data[key].pool?.address ?? "",
tokenPoolVersion: data[key].pool?.version ?? "",
tokenPoolType: (poolInfo?.type ?? data[key].pool?.type ?? "burnMint") as PoolType,
tokenPoolRawType: poolInfo?.rawType ?? data[key].pool?.rawType ?? "",
tokenPoolAddress: poolInfo?.address ?? data[key].pool?.address ?? "",
tokenPoolVersion: poolInfo?.version ?? data[key].pool?.version ?? "",
explorer: network.explorer,
chainType,
}
Expand Down
66 changes: 35 additions & 31 deletions src/components/CCIP/ChainHero/ChainHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,39 +147,43 @@ function ChainHero({
</div>
</div>

<div className="ccip-chain-hero__heading">
<img
src={network?.logo || token?.logo}
alt=""
className={token?.logo ? "ccip-chain-hero__token-logo" : ""}
onError={({ currentTarget }) => {
currentTarget.onerror = null // prevents looping
currentTarget.src = fallbackTokenIconUrl
}}
/>
<h1
style={{
display: "flex",
alignItems: "center",
gap: "8px",
position: "relative",
overflow: "visible",
}}
>
{network?.name || token?.id}
<span className="ccip-chain-hero__token-logo__symbol">
{token?.id === "USDC" ? "USD Coin" : token?.name}
</span>

{chainTooltipConfig && (
<Tooltip
tip={chainTooltipConfig.content}
hoverable={chainTooltipConfig.hoverable}
hideDelay={chainTooltipConfig.hideDelay}
{(network || token) && (
<div className="ccip-chain-hero__heading">
{(network?.logo || token?.logo) && (
<img
src={network?.logo || token?.logo}
alt=""
className={token?.logo ? "ccip-chain-hero__token-logo" : ""}
onError={({ currentTarget }) => {
currentTarget.onerror = null // prevents looping
currentTarget.src = fallbackTokenIconUrl
}}
/>
)}
</h1>
</div>
<h1
style={{
display: "flex",
alignItems: "center",
gap: "8px",
position: "relative",
overflow: "visible",
}}
>
{network?.name || token?.id}
<span className="ccip-chain-hero__token-logo__symbol">
{token?.id === "USDC" ? "USD Coin" : token?.name}
</span>

{chainTooltipConfig && (
<Tooltip
tip={chainTooltipConfig.content}
hoverable={chainTooltipConfig.hoverable}
hideDelay={chainTooltipConfig.hideDelay}
/>
)}
</h1>
</div>
)}
{network && (
<div className="ccip-chain-hero__details">
<div className="ccip-chain-hero__details__item">
Expand Down
3 changes: 1 addition & 2 deletions src/components/CCIP/ChainHero/TokenDetailsHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import Address from "~/components/AddressReact.tsx"
import { getExplorerAddressUrl, fallbackTokenIconUrl } from "~/features/utils/index.ts"
import "./ChainHero.css"
import { ExplorerInfo, ChainType } from "~/config/types.ts"
import { getNetworkIconUrl } from "~/config/data/ccip/data.ts"
import { formatPoolTypeForDisplay } from "~/lib/ccip/graphql/utils/type-version-parser.ts"

interface TokenDetailsHeroProps {
Expand Down Expand Up @@ -31,7 +30,7 @@ function TokenDetailsHero({ network, token, inDrawer = false }: TokenDetailsHero
<div className="ccip-chain-hero__content">
<div className="ccip-chain-hero__heading">
<div className="ccip-chain-hero__heading__images">
<img src={getNetworkIconUrl(network.name)} alt="" />
<img src={network.logo} alt="" />
<img
src={token?.logo}
alt=""
Expand Down
22 changes: 9 additions & 13 deletions src/components/CCIP/Drawer/LaneDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import "../Tables/Table.css"
import { Environment, LaneConfig, LaneFilter } from "~/config/data/ccip/types.ts"
import { getNetwork } from "~/config/data/ccip/data.ts"
import { determineTokenMechanism } from "~/config/data/ccip/utils.ts"
import type { PoolType } from "~/config/data/ccip/types.ts"
import { useState } from "react"
import LaneDetailsHero from "../ChainHero/LaneDetailsHero.tsx"
import { getExplorerAddressUrl, fallbackTokenIconUrl } from "~/features/utils/index.ts"
Expand Down Expand Up @@ -54,7 +55,6 @@ function LaneDrawer({
// Process tokens with hook
const { tokens: processedTokens, count: tokenCount } = useLaneTokens({
tokens: apiTokens,
environment,
rateLimitsData: rateLimits,
inOutbound,
searchQuery: search,
Expand Down Expand Up @@ -216,22 +216,16 @@ function LaneDrawer({
</td>
<td data-clipboard-type="token">
<Address
address={token.data[sourceNetwork.key].tokenAddress}
address={token.tokenAddress}
endLength={4}
contractUrl={getExplorerAddressUrl(explorer)(token.data[sourceNetwork.key].tokenAddress)}
contractUrl={getExplorerAddressUrl(explorer)(token.tokenAddress)}
/>
</td>
<td>{token.data[sourceNetwork.key].decimals}</td>
<td>{token.decimals}</td>
<td>
{inOutbound === LaneFilter.Outbound
? determineTokenMechanism(
token.data[sourceNetwork.key].pool?.type,
token.data[destinationNetwork.key].pool?.type
)
: determineTokenMechanism(
token.data[destinationNetwork.key].pool?.type,
token.data[sourceNetwork.key].pool?.type
)}
? determineTokenMechanism(token.sourcePoolType as PoolType, token.destPoolType as PoolType)
: determineTokenMechanism(token.destPoolType as PoolType, token.sourcePoolType as PoolType)}
</td>

<td>
Expand Down Expand Up @@ -261,7 +255,9 @@ function LaneDrawer({
</tbody>
</table>
</div>
<div className="ccip-table__notFound">{processedTokens.length === 0 && <>No tokens found</>}</div>
<div className="ccip-table__notFound">
{isLoadingRateLimits ? <>Loading...</> : processedTokens.length === 0 && <>No tokens found</>}
</div>
</div>
</>
)
Expand Down
34 changes: 16 additions & 18 deletions src/hooks/useLaneTokens.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { useMemo } from "react"
import { Environment, LaneFilter, Version } from "~/config/data/ccip/types.ts"
import { getTokenData } from "~/config/data/ccip/data.ts"
import { LaneFilter } from "~/config/data/ccip/types.ts"
import { getTokenIconUrl } from "~/features/utils/index.ts"
import { realtimeDataService } from "~/lib/ccip/services/realtime-data-instance.ts"
import type { TokenLaneData } from "~/lib/ccip/types/index.ts"

export interface ProcessedToken {
id: string
data: ReturnType<typeof getTokenData>
tokenAddress: string
decimals: number
sourcePoolType: string
destPoolType: string
logo: string
rateLimits: {
standard: { capacity: string; rate: string; isEnabled: boolean } | null
Expand All @@ -17,13 +20,12 @@ export interface ProcessedToken {

interface UseLaneTokensParams {
tokens: string[] | undefined
environment: Environment
rateLimitsData: Record<string, any>
rateLimitsData: Record<string, TokenLaneData>
inOutbound: LaneFilter
searchQuery: string
}

export function useLaneTokens({ tokens, environment, rateLimitsData, inOutbound, searchQuery }: UseLaneTokensParams) {
export function useLaneTokens({ tokens, rateLimitsData, inOutbound, searchQuery }: UseLaneTokensParams) {
const processedTokens = useMemo(() => {
if (!tokens) return []

Expand All @@ -32,30 +34,26 @@ export function useLaneTokens({ tokens, environment, rateLimitsData, inOutbound,
return tokens
.filter((token) => token.toLowerCase().includes(searchQuery.toLowerCase()))
.map((token) => {
const data = getTokenData({
environment,
version: Version.V1_2_0,
tokenId: token || "",
})

// Skip tokens with no data
if (!Object.keys(data).length) return null
const tokenLaneData = rateLimitsData[token]
if (!tokenLaneData) return null

const logo = getTokenIconUrl(token)
const tokenLaneData = rateLimitsData[token]
const allLimits = realtimeDataService.getAllRateLimitsForDirection(tokenLaneData?.rateLimits, direction)
const allLimits = realtimeDataService.getAllRateLimitsForDirection(tokenLaneData.rateLimits, direction)
const isPaused = allLimits.standard?.capacity === "0"

return {
id: token,
data,
tokenAddress: tokenLaneData.tokenAddress ?? "",
decimals: tokenLaneData.tokenDecimals ?? 0,
sourcePoolType: tokenLaneData.sourcePoolType ?? "",
destPoolType: tokenLaneData.destPoolType ?? "",
logo,
rateLimits: allLimits,
isPaused,
}
})
.filter((token): token is ProcessedToken => token !== null)
}, [tokens, environment, rateLimitsData, inOutbound, searchQuery])
}, [tokens, rateLimitsData, inOutbound, searchQuery])

return {
tokens: processedTokens,
Expand Down
Loading
Loading