diff --git a/.changeset/treasury-composition.md b/.changeset/treasury-composition.md new file mode 100644 index 000000000..0fb2629ec --- /dev/null +++ b/.changeset/treasury-composition.md @@ -0,0 +1,5 @@ +--- +'@buildeross/dao-ui': minor +--- + +Add a treasury composition view to the DAO Treasury tab: an allocation donut and curated asset rows (ETH plus a per-chain registry of common tokens and the DAO's clanker token, valued in USD) read via on-chain multicall; DAO NFT holdings read natively from the Builder subgraph; and an auction-revenue analytics chart. Replaces the Alchemy-dependent token/NFT balance sections with key-free, subgraph/RPC-backed equivalents. diff --git a/packages/dao-ui/src/components/Treasury/NFTBalance.tsx b/packages/dao-ui/src/components/Treasury/NFTBalance.tsx deleted file mode 100644 index c0dfcff7d..000000000 --- a/packages/dao-ui/src/components/Treasury/NFTBalance.tsx +++ /dev/null @@ -1,277 +0,0 @@ -import { PUBLIC_IS_TESTNET } from '@buildeross/constants' -import { ETHERSCAN_BASE_URL } from '@buildeross/constants/etherscan' -import { useEnrichedPinnedAssets } from '@buildeross/hooks/useEnrichedPinnedAssets' -import { useNFTBalance } from '@buildeross/hooks/useNFTBalance' -import { usePinnedAssets } from '@buildeross/hooks/usePinnedAssets' -import { useChainStore, useDaoStore } from '@buildeross/stores' -import { FallbackImage } from '@buildeross/ui/FallbackImage' -import { skeletonAnimation } from '@buildeross/ui/styles' -import { Box, Button, Flex, Grid, Icon, Text } from '@buildeross/zord' -import React, { useMemo, useState } from 'react' - -import { erc721AssetsWrapper } from './Treasury.css' - -export const NFTBalance: React.FC = () => { - const [showSpamNfts, setShowSpamNfts] = useState(PUBLIC_IS_TESTNET) - const { addresses } = useDaoStore() - const owner = addresses.treasury - const chain = useChainStore((x) => x.chain) - const { nfts: allNfts, isLoading: nftsLoading } = useNFTBalance(chain.id, owner, { - filterSpam: !showSpamNfts, - }) - - // Fetch pinned assets - const { pinnedAssets, isLoading: pinnedLoading } = usePinnedAssets( - chain.id, - addresses.token - ) - - // Filter NFT pinned assets (ERC721 and ERC1155) - const pinnedNFTs = useMemo( - () => - pinnedAssets?.filter( - (p) => (p.tokenType === 1 || p.tokenType === 2) && !p.revoked - ) || [], - [pinnedAssets] - ) - - // Fetch enriched pinned NFTs - const { enrichedPinnedAssets, isLoading: enrichedLoading } = useEnrichedPinnedAssets( - chain.id, - addresses.treasury, - pinnedNFTs - ) - - // Combine and dedupe NFTs with pinned assets - const allNftsWithPinned = useMemo(() => { - if (!allNfts && !enrichedPinnedAssets) return [] - - const nftMap = new Map() - - // Add standard NFTs - allNfts?.forEach((nft) => { - const key = `${nft.contract.address.toLowerCase()}-${nft.tokenId}` - nftMap.set(key, { - ...nft, - isPinned: false, - }) - }) - - // Add/override with pinned NFTs (ensures low-value pinned NFTs appear) - enrichedPinnedAssets?.forEach((asset) => { - if (asset.isCollection) { - // For collection pins, mark all NFTs from that collection as pinned - nftMap.forEach((nft, key) => { - if (nft.contract.address.toLowerCase() === asset.token.toLowerCase()) { - nftMap.set(key, { ...nft, isPinned: true }) - } - }) - } else { - // For individual NFT pins - const key = `${asset.token.toLowerCase()}-${asset.tokenId}` - const existing = nftMap.get(key) - - nftMap.set(key, { - name: asset.nftName || existing?.name || '', - tokenId: asset.tokenId || existing?.tokenId || '', - contract: { - address: asset.token, - }, - collection: { - name: existing?.collection?.name || '', - }, - image: { - originalUrl: existing?.image?.originalUrl || asset.nftImage || '', - }, - tokenType: asset.tokenType === 1 ? 'ERC721' : 'ERC1155', - balance: existing?.balance || '1', - isPinned: true, - }) - } - }) - - return Array.from(nftMap.values()) - }, [allNfts, enrichedPinnedAssets]) - - // Sort: pinned first, then original order - const sortedNfts = useMemo( - () => - [...allNftsWithPinned].sort((a, b) => { - if (a.isPinned && !b.isPinned) return -1 - if (!a.isPinned && b.isPinned) return 1 - return 0 - }), - [allNftsWithPinned] - ) - - const numNfts = sortedNfts?.length ?? 0 - const isLoading = nftsLoading || pinnedLoading || enrichedLoading - - const nfts = sortedNfts - - return ( - <> - - - NFTs - - - - - {isLoading && numNfts === 0 && ( - - {Array.from({ length: 6 }).map((_, index) => ( - - ))} - - )} - - {!isLoading && numNfts === 0 && ( - - - No NFTs Found - - - )} - - {numNfts > 0 && ( - - {nfts?.map((nft) => { - const originalUrl = nft.image.originalUrl - if (!originalUrl) return null - const url = - ETHERSCAN_BASE_URL[chain.id] + - '/token/' + - nft.contract.address + - '?a=' + - owner - return ( - - - - - - - - - {nft.name ?? '‎ '} - - {nft.isPinned && } - - {nft.tokenType === 'ERC1155' && ( - - {nft.balance} - - )} - - - {nft.collection?.name ?? '‎ '} - - - - ) - })} - - )} - - ) -} diff --git a/packages/dao-ui/src/components/Treasury/TokenBalance.tsx b/packages/dao-ui/src/components/Treasury/TokenBalance.tsx deleted file mode 100644 index 04c5d4b0b..000000000 --- a/packages/dao-ui/src/components/Treasury/TokenBalance.tsx +++ /dev/null @@ -1,267 +0,0 @@ -import { PUBLIC_IS_TESTNET } from '@buildeross/constants' -import { ETHERSCAN_BASE_URL } from '@buildeross/constants/etherscan' -import { useEnrichedPinnedAssets } from '@buildeross/hooks/useEnrichedPinnedAssets' -import { usePinnedAssets } from '@buildeross/hooks/usePinnedAssets' -import { useTokenBalances } from '@buildeross/hooks/useTokenBalances' -import { useChainStore, useDaoStore } from '@buildeross/stores' -import { Avatar, NameAvatar } from '@buildeross/ui/Avatar' -import { skeletonAnimation } from '@buildeross/ui/styles' -import { formatCryptoVal } from '@buildeross/utils/numbers' -import { Box, Button, Flex, Grid, Icon, Text } from '@buildeross/zord' -import React, { useMemo, useState } from 'react' -import { formatUnits } from 'viem' - -import { statisticContent } from '../../styles/About.css' -import { erc20AssetsWrapper } from './Treasury.css' - -export const TokenBalance: React.FC = () => { - const [showLowValueTokens, setShowLowValueTokens] = useState(PUBLIC_IS_TESTNET) - const { addresses } = useDaoStore() - const chain = useChainStore((x) => x.chain) - const owner = addresses.treasury - const { balances, isLoading: balancesLoading } = useTokenBalances( - chain.id, - addresses.treasury, - { filterLowValue: !showLowValueTokens } - ) - - // Fetch pinned assets - const { pinnedAssets, isLoading: pinnedLoading } = usePinnedAssets( - chain.id, - addresses.token - ) - - // Filter ERC20 pinned assets - const pinnedERC20 = useMemo( - () => pinnedAssets?.filter((p) => p.tokenType === 0 && !p.revoked) || [], - [pinnedAssets] - ) - - // Fetch enriched pinned assets - const { enrichedPinnedAssets, isLoading: enrichedLoading } = useEnrichedPinnedAssets( - chain.id, - addresses.treasury, - pinnedERC20 - ) - - // Combine and dedupe balances with pinned assets - const allTokens = useMemo(() => { - if (!balances && !enrichedPinnedAssets) return [] - - const tokenMap = new Map() - - // Add standard balances - balances?.forEach((token) => { - tokenMap.set(token.address.toLowerCase(), { - ...token, - isPinned: false, - }) - }) - - // Add/override with pinned assets (ensures low-value pinned assets appear) - enrichedPinnedAssets?.forEach((asset) => { - const key = asset.token.toLowerCase() - const existing = tokenMap.get(key) - - tokenMap.set(key, { - address: asset.token, - balance: asset.balance || existing?.balance || '0', - name: asset.name || existing?.name || '', - symbol: asset.symbol || existing?.symbol || '', - decimals: asset.decimals || existing?.decimals || 18, - logo: asset.logo || existing?.logo || '', - price: asset.price || existing?.price || '0', - valueInUSD: asset.valueInUSD || existing?.valueInUSD || '0', - isPinned: true, - }) - }) - - return Array.from(tokenMap.values()) - }, [balances, enrichedPinnedAssets]) - - // Sort: pinned first, then by USD value - const sortedBalances = useMemo( - () => - [...allTokens].sort((a, b) => { - if (a.isPinned && !b.isPinned) return -1 - if (!a.isPinned && b.isPinned) return 1 - return parseFloat(b.valueInUSD) - parseFloat(a.valueInUSD) - }), - [allTokens] - ) - - const totalUSD = sortedBalances - ?.reduce((acc, balance) => acc + parseFloat(balance.valueInUSD), 0) - .toFixed(2) - - const numBalances = sortedBalances?.length ?? 0 - const isLoading = balancesLoading || pinnedLoading || enrichedLoading - - return ( - <> - - - Tokens - - - {numBalances > 0 && ( - - ${totalUSD ? totalUSD : ' '} - - )} - - - - - {isLoading && numBalances === 0 && ( - - {Array.from({ length: 4 }).map((_, index) => ( - - ))} - - )} - - {!isLoading && numBalances === 0 && ( - - - No Tokens Found - - - )} - - {numBalances > 0 && ( - - - - Asset - - - Balance - - - Value in USD - - - {sortedBalances?.map((tokenBalance) => { - const url = - ETHERSCAN_BASE_URL[chain.id] + - '/token/' + - tokenBalance.address + - '?a=' + - owner - - const value = ( - <> - - {formatCryptoVal( - formatUnits(BigInt(tokenBalance.balance), tokenBalance.decimals) - )}{' '} - {tokenBalance.symbol} - - ${tokenBalance.valueInUSD} - - ) - - const name = ( - - {tokenBalance.logo ? ( - - ) : ( - - )} - - {tokenBalance.name} - {tokenBalance.isPinned && } - - - ) - return ( - - - {name} - - {value} - - - - {name} - {value} - - - ) - })} - - )} - - ) -} diff --git a/packages/dao-ui/src/components/Treasury/Treasury.tsx b/packages/dao-ui/src/components/Treasury/Treasury.tsx index e9c192bbd..5f1007e84 100644 --- a/packages/dao-ui/src/components/Treasury/Treasury.tsx +++ b/packages/dao-ui/src/components/Treasury/Treasury.tsx @@ -12,9 +12,11 @@ import { useBalance } from 'wagmi' import { statisticContent } from '../../styles/About.css' import { activitySection } from '../../styles/Section.css' -import { NFTBalance } from './NFTBalance' -import { TokenBalance } from './TokenBalance' import { treasuryWrapper } from './Treasury.css' +import { TreasuryAnalytics } from './TreasuryAnalytics' +import { TreasuryComposition } from './TreasuryComposition' +import { TreasuryNfts } from './TreasuryNfts' +import { TreasuryRecentTransactions } from './TreasuryRecentTransactions' export const Treasury = () => { const { addresses } = useDaoStore() @@ -135,8 +137,10 @@ export const Treasury = () => { - - + + + + ) } diff --git a/packages/dao-ui/src/components/Treasury/TreasuryAnalytics.css.ts b/packages/dao-ui/src/components/Treasury/TreasuryAnalytics.css.ts new file mode 100644 index 000000000..d1e5d51d9 --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/TreasuryAnalytics.css.ts @@ -0,0 +1,97 @@ +import { skeletonAnimation } from '@buildeross/ui/styles' +import { vars } from '@buildeross/zord' +import { style, styleVariants } from '@vanilla-extract/css' + +export const metricsGrid = style({ + gridTemplateColumns: 'repeat(4, 1fr)', + gridGap: '0.5rem', + '@media': { + 'screen and (max-width: 768px)': { + gridTemplateColumns: 'repeat(2, 1fr)', + }, + }, +}) + +const tabBase = style({ + textTransform: 'capitalize', + width: 'fit-content', + borderRadius: '0px !important', + selectors: { + '&:not([disabled]):hover': { + backgroundColor: 'transparent !important', + }, + }, +}) + +export const windowTab = styleVariants({ + selected: [tabBase, { borderBottom: `2px solid ${vars.color.text1} !important` }], + unselected: [tabBase, { borderBottom: '2px solid transparent !important' }], +}) + +export const chartBox = style({ + width: '100%', + height: '260px', + '@media': { + 'screen and (max-width: 768px)': { + height: '180px', + }, + }, +}) + +export const chartSvg = style({ + display: 'block', + width: '100%', + height: 'auto', + overflow: 'visible', +}) + +export const chartLine = style({ + fill: 'none', + stroke: vars.color.text1, + strokeWidth: 2, + strokeLinejoin: 'round', + strokeLinecap: 'round', + vectorEffect: 'non-scaling-stroke', +}) + +// Theme-agnostic translucent grays so gridlines stay visible in both +// light and dark themes (the `border` token goes near-invisible on dark). +export const chartGrid = style({ + stroke: 'rgba(128, 128, 128, 0.2)', + strokeWidth: 1, + vectorEffect: 'non-scaling-stroke', +}) + +export const chartBaseline = style({ + stroke: 'rgba(128, 128, 128, 0.45)', + strokeWidth: 1, + vectorEffect: 'non-scaling-stroke', +}) + +export const chartAxisLabel = style({ + fill: vars.color.text3, + fontSize: '14px', + fontFamily: 'inherit', +}) + +export const chartGradientTop = style({ + stopColor: vars.color.text1, + stopOpacity: 0.16, +}) + +export const chartGradientBottom = style({ + stopColor: vars.color.text1, + stopOpacity: 0, +}) + +export const chartSkeleton = style({ + animation: skeletonAnimation, + width: '100%', + height: '260px', + borderRadius: vars.radii.curved, + '@media': { + 'screen and (max-width: 768px)': { + height: '180px', + }, + }, +}) diff --git a/packages/dao-ui/src/components/Treasury/TreasuryAnalytics.tsx b/packages/dao-ui/src/components/Treasury/TreasuryAnalytics.tsx new file mode 100644 index 000000000..dfe818979 --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/TreasuryAnalytics.tsx @@ -0,0 +1,264 @@ +import { BASE_URL } from '@buildeross/constants/baseUrl' +import { SWR_KEYS } from '@buildeross/constants/swrKeys' +import { AuctionHistoryQuery } from '@buildeross/sdk/subgraph' +import { useChainStore, useDaoStore } from '@buildeross/stores' +import { formatCryptoVal } from '@buildeross/utils/numbers' +import { Box, Button, Flex, Grid, Text } from '@buildeross/zord' +import axios from 'axios' +import React, { useMemo, useState } from 'react' +import useSWR from 'swr' + +import { statisticContent } from '../../styles/About.css' +import { + chartAxisLabel, + chartBaseline, + chartBox, + chartGradientBottom, + chartGradientTop, + chartGrid, + chartLine, + chartSkeleton, + chartSvg, + metricsGrid, + windowTab, +} from './TreasuryAnalytics.css' +import { + type AuctionDatum, + buildChartPaths, + buildYTicks, + computeCumulativeRevenue, + computeTreasuryMetrics, +} from './treasuryAnalytics.helper' + +enum RevenueWindow { + '30d' = '30', + '60d' = '60', + '90d' = '90', + 'All' = '0', +} + +const WINDOW_LABELS: Record = { + [RevenueWindow['30d']]: '30d', + [RevenueWindow['60d']]: '60d', + [RevenueWindow['90d']]: '90d', + [RevenueWindow['All']]: 'All', +} + +const VIEW_W = 800 +const VIEW_H = 340 +const MARGIN = { top: 16, right: 20, bottom: 32, left: 56 } +const PLOT_W = VIEW_W - MARGIN.left - MARGIN.right +const PLOT_H = VIEW_H - MARGIN.top - MARGIN.bottom + +const GRADIENT_ID = 'treasuryRevGradient' + +const formatAxisDate = (unixSeconds: number): string => + new Date(unixSeconds * 1000).toLocaleDateString('en-US', { + month: 'short', + year: '2-digit', + }) + +const startTimeFromNow = (windowKey: RevenueWindow): number => { + if (windowKey === RevenueWindow['All']) return 0 + const nowInSeconds = Math.floor(Date.now() / 1000) + return nowInSeconds - parseInt(windowKey) * 24 * 60 * 60 +} + +const Metric: React.FC<{ label: string; value: string }> = ({ label, value }) => ( + + + {value} + + + {label} + + +) + +export const TreasuryAnalytics = () => { + const chain = useChainStore((x) => x.chain) + const { + addresses: { token }, + } = useDaoStore() + + const [selectedWindow, setSelectedWindow] = useState(RevenueWindow['All']) + + const { data, isValidating, error } = useSWR( + token && chain.id + ? ([ + SWR_KEYS.AUCTION_HISTORY, + 'treasury-analytics', + token, + chain.id, + selectedWindow, + ] as const) + : null, + async ([, , _token, _chainId, _window]) => { + // The endpoint returns at most PAGE auctions, ordered oldest-first + // (endTime ASC). For high-volume DAOs (1000+ auctions) a single call + // undercounts revenue, so page through using each batch's last endTime + // as the next cursor (the query filters endTime_gt startTime). + const PAGE = 1000 + const MAX_PAGES = 25 + const byId = new Map() + let cursor = startTimeFromNow(_window) + + for (let page = 0; page < MAX_PAGES; page++) { + const { data } = await axios.get<{ auctionHistory: AuctionHistoryQuery }>( + `${BASE_URL}/api/auctionHistory/${_token}?chainId=${_chainId}&startTime=${cursor}`, + { timeout: 15_000 } + ) + const batch = data.auctionHistory.dao?.auctions ?? [] + if (batch.length === 0) break + + for (const auction of batch) { + byId.set(auction.id, { + id: auction.id, + endTime: Number(auction.endTime), + winningBidAmt: auction?.winningBid?.amount ?? '0', + }) + } + + if (batch.length < PAGE) break + const lastEndTime = Number(batch[batch.length - 1].endTime) + if (lastEndTime === cursor) break // no forward progress — stop + cursor = lastEndTime + } + + return Array.from(byId.values()) + }, + { revalidateOnFocus: false } + ) + + const { metrics, paths, yTicks, startLabel, endLabel, hasChart } = useMemo(() => { + const auctions = data ?? [] + const series = computeCumulativeRevenue(auctions) + const maxY = series.length ? series[series.length - 1].cumulative : 0 + return { + metrics: computeTreasuryMetrics(auctions), + paths: buildChartPaths(series, PLOT_W, PLOT_H), + yTicks: buildYTicks(maxY, 4), + startLabel: series.length ? formatAxisDate(series[0].endTime) : '', + endLabel: series.length ? formatAxisDate(series[series.length - 1].endTime) : '', + hasChart: series.length >= 2, + } + }, [data]) + + return ( + + + + Auction Revenue + + + {Object.values(RevenueWindow).map((w) => ( + + ))} + + + + + {isValidating && !data ? ( + + ) : error && !data ? ( + + + Couldn't load auction revenue. Please try again later. + + + ) : hasChart ? ( + + + + + + + + + {yTicks.map((tick) => { + const y = PLOT_H * (1 - tick.fraction) + return ( + + + + {formatCryptoVal(tick.value)} + + + ) + })} + + + + {startLabel} + + + {endLabel} + + + + ) : ( + + + Not enough settled auctions in this window to chart revenue. + + + )} + + + + + + + + + + + + ) +} diff --git a/packages/dao-ui/src/components/Treasury/TreasuryComposition.css.ts b/packages/dao-ui/src/components/Treasury/TreasuryComposition.css.ts new file mode 100644 index 000000000..b1fe11e7b --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/TreasuryComposition.css.ts @@ -0,0 +1,206 @@ +import { vars } from '@buildeross/zord' +import { style } from '@vanilla-extract/css' + +export const layout = style({ + display: 'grid', + gridTemplateColumns: '320px 1fr', + gap: '1rem', + alignItems: 'start', + '@media': { + 'screen and (max-width: 900px)': { + gridTemplateColumns: '1fr', + }, + }, +}) + +/** + * Few-asset fallback: the 320px|1fr grid leaves a sparse, lopsided right column + * when a DAO holds only one or two priced assets. Stack the donut over the + * rows in a single centered, width-matched column instead so the two pieces + * line up rather than a narrow donut sitting over a full-width row. + */ +export const layoutStacked = style({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + width: '100%', + maxWidth: '460px', + marginLeft: 'auto', + marginRight: 'auto', +}) + +export const donutCard = style({ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + borderStyle: 'solid', + borderWidth: '1px', + borderColor: vars.color.border, + borderRadius: vars.radii.curved, + padding: '1.5rem', +}) + +export const donutWrap = style({ + position: 'relative', + width: '240px', + height: '240px', +}) + +export const donutSvg = style({ + width: '100%', + height: '100%', +}) + +export const donutSlice = style({ + transition: 'stroke-width 0.12s ease', +}) + +export const donutCenter = style({ + position: 'absolute', + inset: 0, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + gap: '2px', + pointerEvents: 'none', +}) + +export const donutCenterLabel = style({ + fontSize: '11px', + fontWeight: 600, + textTransform: 'uppercase', + letterSpacing: '0.06em', + color: vars.color.text3, +}) + +export const donutCenterValue = style({ + fontSize: '30px', + fontWeight: 700, + lineHeight: 1, + letterSpacing: '-0.02em', + color: vars.color.text1, +}) + +export const donutCenterSub = style({ + fontSize: '12px', + color: vars.color.text3, +}) + +export const rows = style({ + display: 'flex', + flexDirection: 'column', + gap: '0.75rem', +}) + +export const row = style({ + display: 'grid', + gridTemplateColumns: '40px 1.4fr 1fr 1.2fr', + alignItems: 'center', + columnGap: '1rem', + rowGap: '0.5rem', + borderStyle: 'solid', + borderWidth: '1px', + borderColor: vars.color.border, + borderRadius: vars.radii.curved, + padding: '0.85rem 1.1rem', + '@media': { + 'screen and (max-width: 600px)': { + gridTemplateColumns: '32px 1fr auto', + }, + }, +}) + +export const tokenBadge = style({ + width: '36px', + height: '36px', + borderRadius: vars.radii.round, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + fontSize: '11px', + fontWeight: 700, + color: vars.color.text1, + background: vars.color.background2, +}) + +export const rowName = style({ fontWeight: 600, color: vars.color.text1 }) +export const rowSub = style({ + fontSize: '12px', + color: vars.color.text3, + marginTop: '2px', +}) + +export const rowBalance = style({ + fontVariantNumeric: 'tabular-nums', + fontSize: '14px', + textAlign: 'right', + color: vars.color.text1, +}) + +export const rowUsdWrap = style({ + '@media': { + 'screen and (max-width: 600px)': { + display: 'none', + }, + }, +}) + +export const rowUsd = style({ + fontVariantNumeric: 'tabular-nums', + fontSize: '13px', + textAlign: 'right', + color: vars.color.text3, + marginBottom: '4px', +}) + +export const barTrack = style({ + height: '4px', + width: '100%', + borderRadius: vars.radii.round, + overflow: 'hidden', + background: vars.color.background2, +}) + +export const barFill = style({ + height: '100%', + borderRadius: vars.radii.round, + transition: 'width 0.2s ease', +}) + +export const rowPct = style({ + fontSize: '11px', + textAlign: 'right', + color: vars.color.text3, + marginTop: '4px', + fontVariantNumeric: 'tabular-nums', +}) + +export const legend = style({ + display: 'flex', + flexDirection: 'column', + gap: '0.6rem', + marginTop: '1.25rem', + width: '100%', +}) + +export const legendItem = style({ + display: 'grid', + gridTemplateColumns: '14px 1fr auto', + alignItems: 'center', + gap: '0.6rem', + fontSize: '13px', + color: vars.color.text2, +}) + +export const legendDot = style({ + width: '12px', + height: '12px', + borderRadius: '3px', +}) + +export const legendPct = style({ + fontVariantNumeric: 'tabular-nums', + fontSize: '12px', + color: vars.color.text3, +}) diff --git a/packages/dao-ui/src/components/Treasury/TreasuryComposition.tsx b/packages/dao-ui/src/components/Treasury/TreasuryComposition.tsx new file mode 100644 index 000000000..42f8ed8da --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/TreasuryComposition.tsx @@ -0,0 +1,349 @@ +'use client' + +import { SWR_KEYS } from '@buildeross/constants/swrKeys' +import { useEthUsdPrice } from '@buildeross/hooks' +import { daoClankerTokensRequest } from '@buildeross/sdk/subgraph' +import { useChainStore, useDaoStore } from '@buildeross/stores' +import type { AddressType } from '@buildeross/types' +import { Box, Flex, Text } from '@buildeross/zord' +import React, { useMemo, useRef, useState } from 'react' +import useSWR from 'swr' +import { erc20Abi, formatEther } from 'viem' +import { useBalance, useReadContracts } from 'wagmi' + +import { tokenLogo } from './tokenLogos' +import { + barFill, + barTrack, + donutCard, + donutCenter, + donutCenterLabel, + donutCenterSub, + donutCenterValue, + donutSlice, + donutSvg, + donutWrap, + layout, + layoutStacked, + legend, + legendDot, + legendItem, + legendPct, + row, + rowBalance, + rowName, + rowPct, + rows, + rowSub, + rowUsd, + rowUsdWrap, + tokenBadge, +} from './TreasuryComposition.css' +import { + computeDonutArcs, + type DonutSlice, + formatTokenAmount, + formatUsd, + sliceColor, + tokenUsdValue, +} from './treasuryComposition.helper' +import { COMMON_TREASURY_TOKENS, type TreasuryToken } from './treasuryTokens' + +type RegistryToken = TreasuryToken & { logo?: string } + +const DONUT_SIZE = 240 +const DONUT_THICKNESS = 40 + +interface Asset { + symbol: string + address: string + sub: string + balanceLabel: string + usd: number + color: string + logo?: string +} + +export const TreasuryComposition = () => { + const { addresses } = useDaoStore() + const chain = useChainStore((x) => x.chain) + const treasury = addresses.treasury as AddressType | undefined + const token = addresses.token as AddressType | undefined + + const { price: ethUsd } = useEthUsdPrice() + const { data: ethBalance } = useBalance({ + address: treasury as `0x${string}` | undefined, + chainId: chain.id, + }) + + // Discover the DAO's own clanker token(s) dynamically — no per-DAO config. + const { data: clankerTokens } = useSWR( + token && chain.id + ? ([SWR_KEYS.CLANKER_TOKENS, 'treasury', chain.id, token] as const) + : null, + ([, , _chainId, _token]) => daoClankerTokensRequest(_token, _chainId) + ) + + // Global per-chain registry + this DAO's clanker token(s), deduped. + const tokenList = useMemo(() => { + const common = COMMON_TREASURY_TOKENS[chain.id] ?? [] + const seen = new Set(common.map((t) => t.address.toLowerCase())) + const clankers: RegistryToken[] = (clankerTokens ?? []) + .filter((c) => c.tokenAddress && !seen.has(c.tokenAddress.toLowerCase())) + .map((c) => ({ + symbol: c.tokenSymbol || 'TOKEN', + address: c.tokenAddress.toLowerCase() as `0x${string}`, + decimals: 18, + kind: 'other' as const, + logo: c.tokenImage || undefined, + })) + return [...common, ...clankers] + }, [chain.id, clankerTokens]) + + const { data: balances } = useReadContracts({ + allowFailure: true, + contracts: tokenList.map((t) => ({ + address: t.address, + abi: erc20Abi, + functionName: 'balanceOf' as const, + args: [treasury as `0x${string}`], + chainId: chain.id, + })), + // Treasury balances change rarely, so don't poll: the app sets a global 5s + // refetchInterval, and at that cadence an occasional failed read would drop a + // token row for a cycle, so rows visibly blinked. They still refresh on + // mount/focus, and the per-token last-good cache below keeps a row visible + // across a failed read (without ever showing another DAO's balance). + query: { + enabled: !!treasury && tokenList.length > 0, + refetchInterval: false, + staleTime: 30_000, + }, + }) + + // Last known-good balance per token address. `allowFailure` reads can come back + // as `failure` (or a clanker token can arrive a beat later than the commons), + // which would otherwise zero the balance and drop the row. Keyed by address and + // reset when the DAO changes, so a stale value never leaks across treasuries — + // resetting during render (not in an effect) means it's cleared before the + // memo below reads it, so the switch never shows the previous DAO's numbers. + const daoKey = `${chain.id}:${treasury ?? ''}` + const lastGood = useRef<{ key: string; map: Record }>({ + key: daoKey, + map: {}, + }) + if (lastGood.current.key !== daoKey) { + lastGood.current = { key: daoKey, map: {} } + } + + const { ethAsset, tokenAssets, totalUsd } = useMemo(() => { + const price = ethUsd ?? 0 + const ethRaw = ethBalance?.value ?? 0n + const ethUsdVal = Number(formatEther(ethRaw)) * price + const eth: Asset = { + symbol: 'ETH', + address: 'eth', + sub: 'Native asset', + balanceLabel: `${formatTokenAmount(ethRaw, 18)} ETH`, + usd: ethUsdVal, + color: sliceColor('ETH', 0), + logo: tokenLogo('ETH'), + } + + const assets: Asset[] = tokenList + .map((t, i) => { + const key = t.address.toLowerCase() + const entry = balances?.[i] + let raw: bigint + if (entry?.status === 'success' && typeof entry.result === 'bigint') { + raw = entry.result + lastGood.current.map[key] = raw + } else { + // Failed read or not-yet-fetched token: reuse this token's last good + // value so its row stays put instead of flickering to zero. + raw = lastGood.current.map[key] ?? 0n + } + return { t, raw, i } + }) + .filter(({ raw }) => raw > 0n) + .map(({ t, raw, i }) => ({ + symbol: t.symbol, + address: t.address, + sub: + t.kind === 'stable' + ? 'Stable reserve' + : t.kind === 'weth' + ? 'Wrapped' + : 'ERC-20', + balanceLabel: `${formatTokenAmount(raw, t.decimals)} ${t.symbol}`, + usd: tokenUsdValue(raw, t.decimals, t.kind, price), + color: sliceColor(t.symbol, i + 1), + logo: tokenLogo(t.symbol) ?? t.logo, + })) + .sort((a, b) => b.usd - a.usd) + + const total = eth.usd + assets.reduce((s, a) => s + a.usd, 0) + return { ethAsset: eth, tokenAssets: assets, totalUsd: total } + }, [tokenList, balances, ethBalance, ethUsd]) + + const allAssets = [ethAsset, ...tokenAssets] + + const slices: DonutSlice[] = allAssets + .filter((a) => a.usd > 0) + .map((a) => ({ name: a.symbol, color: a.color, value: a.usd })) + + const hasUsd = totalUsd > 0 + // With only one or two assets the 320px|1fr grid looks lopsided; stack it. + const stacked = allAssets.length <= 2 + + if (!treasury) return null + + return ( + + + + Composition + + {hasUsd && ( + + {formatUsd(totalUsd)} across {slices.length} asset + {slices.length !== 1 ? 's' : ''} + + )} + + + + + {hasUsd ? ( + + ) : ( + + USD prices unavailable — showing balances only. + + )} + + + + {allAssets.map((a) => ( + 0 ? a.usd / totalUsd : 0} + showUsd={hasUsd} + /> + ))} + + + + ) +} + +const AssetRow: React.FC<{ asset: Asset; pct: number; showUsd: boolean }> = ({ + asset, + pct, + showUsd, +}) => ( + + {asset.logo ? ( + {asset.symbol} + ) : ( + + {asset.symbol.slice(0, 4)} + + )} +
+
{asset.symbol}
+
{asset.sub}
+
+
{asset.balanceLabel}
+ {showUsd && ( +
+
{formatUsd(asset.usd)}
+
+
+
+
{(pct * 100).toFixed(1)}%
+
+ )} + +) + +const Donut: React.FC<{ slices: DonutSlice[]; totalUsd: number }> = ({ + slices, + totalUsd, +}) => { + const [hovered, setHovered] = useState(null) + const r = DONUT_SIZE / 2 - DONUT_THICKNESS / 2 - 2 + const C = 2 * Math.PI * r + const arcs = computeDonutArcs(slices, C) + const active = hovered !== null ? slices[hovered] : null + + return ( + <> +
+ + + {arcs.map((arc, i) => ( + setHovered(i)} + onMouseLeave={() => setHovered(null)} + aria-label={`${slices[i].name}: ${formatUsd(slices[i].value)}`} + /> + ))} + +
+
{active ? active.name : 'Total value'}
+
+ {formatUsd(active ? active.value : totalUsd)} +
+
+ {active + ? `${((active.value / totalUsd) * 100).toFixed(1)}% of treasury` + : `across ${slices.length} asset${slices.length !== 1 ? 's' : ''}`} +
+
+
+ +
+ {slices.map((s, i) => ( +
+ + {s.name} + {((s.value / totalUsd) * 100).toFixed(1)}% +
+ ))} +
+ + ) +} diff --git a/packages/dao-ui/src/components/Treasury/TreasuryNfts.css.ts b/packages/dao-ui/src/components/Treasury/TreasuryNfts.css.ts new file mode 100644 index 000000000..08c43eb5e --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/TreasuryNfts.css.ts @@ -0,0 +1,49 @@ +import { vars } from '@buildeross/zord' +import { style } from '@vanilla-extract/css' + +export const grid = style({ + display: 'grid', + gridTemplateColumns: 'repeat(4, 1fr)', + gap: '1rem', + '@media': { + 'screen and (max-width: 900px)': { gridTemplateColumns: 'repeat(3, 1fr)' }, + 'screen and (max-width: 560px)': { gridTemplateColumns: 'repeat(2, 1fr)' }, + }, +}) + +export const card = style({ + borderStyle: 'solid', + borderWidth: '1px', + borderColor: vars.color.border, + borderRadius: vars.radii.curved, + overflow: 'hidden', +}) + +export const image = style({ + display: 'block', + width: '100%', + aspectRatio: '1 / 1', + objectFit: 'cover', + background: vars.color.background2, +}) + +export const cardLabel = style({ + padding: '0.5rem 0.7rem', + fontSize: '13px', + fontWeight: 600, + color: vars.color.text1, + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', +}) + +export const emptyBox = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + minHeight: '120px', + borderStyle: 'solid', + borderWidth: '1px', + borderColor: vars.color.border, + borderRadius: vars.radii.curved, +}) diff --git a/packages/dao-ui/src/components/Treasury/TreasuryNfts.tsx b/packages/dao-ui/src/components/Treasury/TreasuryNfts.tsx new file mode 100644 index 000000000..e1b260874 --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/TreasuryNfts.tsx @@ -0,0 +1,78 @@ +'use client' + +import { tokensQuery } from '@buildeross/sdk/subgraph' +import { useChainStore, useDaoStore } from '@buildeross/stores' +import type { AddressType } from '@buildeross/types' +import { FallbackImage } from '@buildeross/ui/FallbackImage' +import { Box, Flex, Text } from '@buildeross/zord' +import React from 'react' +import useSWR from 'swr' + +import { card, cardLabel, emptyBox, grid, image } from './TreasuryNfts.css' + +/** + * The DAO's own NFTs held in the treasury, read natively from the Builder + * subgraph (`tokensQuery` filtered by owner = treasury). Unlike the Alchemy + * NFT path this needs no API key, isn't spam-flagged, and can't 500 on large + * treasuries — the subgraph already indexes every token the DAO mints. + */ +export const TreasuryNfts = () => { + const { addresses } = useDaoStore() + const chain = useChainStore((x) => x.chain) + const treasury = addresses.treasury as AddressType | undefined + + const { data, isValidating, error } = useSWR( + treasury && chain.id ? (['treasury-dao-nfts', chain.id, treasury] as const) : null, + ([, _chainId, _treasury]) => tokensQuery(_chainId, _treasury), + { revalidateOnFocus: false } + ) + + const tokens = data?.tokens ?? [] + + if (!treasury) return null + + // A subgraph/network failure must read as an error, not "no NFTs" — otherwise + // a fetch failure is indistinguishable from a legitimately empty treasury. + const emptyMessage = error + ? "Couldn't load treasury NFTs. Please try again later." + : isValidating + ? 'Loading…' + : 'No DAO NFTs held in the treasury.' + + return ( + + + + NFTs + + {tokens.length > 0 && ( + + {tokens.length} + {data?.hasNextPage ? '+' : ''} in treasury + + )} + + + {tokens.length === 0 ? ( + + + {emptyMessage} + + + ) : ( + + {tokens.map((t) => ( + + +
{t.name || `#${t.tokenId}`}
+
+ ))} +
+ )} +
+ ) +} diff --git a/packages/dao-ui/src/components/Treasury/TreasuryRecentTransactions.css.ts b/packages/dao-ui/src/components/Treasury/TreasuryRecentTransactions.css.ts new file mode 100644 index 000000000..092216126 --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/TreasuryRecentTransactions.css.ts @@ -0,0 +1,108 @@ +import { vars } from '@buildeross/zord' +import { style } from '@vanilla-extract/css' + +export const card = style({ + display: 'flex', + flexDirection: 'column', + borderStyle: 'solid', + borderWidth: '1px', + borderColor: vars.color.border, + borderRadius: vars.radii.curved, + padding: '1.25rem 1.4rem', +}) + +export const header = style({ marginBottom: '0.35rem' }) + +export const title = style({ fontSize: '16px', fontWeight: 700, color: vars.color.text1 }) + +export const sub = style({ fontSize: '12.5px', color: vars.color.text3 }) + +export const row = style({ + display: 'grid', + gridTemplateColumns: '26px 1fr auto auto', + alignItems: 'center', + gap: '0.75rem', + paddingTop: '0.7rem', + paddingBottom: '0.7rem', + borderBottomStyle: 'solid', + borderBottomWidth: '1px', + borderBottomColor: vars.color.border, +}) + +/** + * Last row has no divider. Set explicitly rather than with `:last-of-type` — + * linked rows render as , same element type as the "View all" link below. + */ +export const rowLast = style({ borderBottom: 'none' }) + +/** Rows that carry a tx hash link out to the block explorer. */ +export const rowLink = style({ + textDecoration: 'none', + color: 'inherit', + cursor: 'pointer', + transition: 'background 0.15s ease', + marginLeft: '-0.6rem', + marginRight: '-0.6rem', + paddingLeft: '0.6rem', + paddingRight: '0.6rem', + borderRadius: vars.radii.small, + selectors: { + // Neutral tint reads as a subtle highlight in both light and dark themes, + // where `background2` is heavy enough to compete with the card itself. + '&:hover': { background: 'rgba(128,128,128,0.12)' }, + }, +}) + +export const badge = style({ + width: '26px', + height: '26px', + borderRadius: vars.radii.round, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + fontSize: '13px', + fontWeight: 700, + flexShrink: 0, +}) + +export const badgeIn = style({ background: 'rgba(16,185,129,0.18)', color: '#0a7d55' }) +export const badgeOut = style({ background: 'rgba(239,68,68,0.16)', color: '#dc2626' }) + +export const txTitle = style({ + fontSize: '13.5px', + color: vars.color.text1, + fontWeight: 500, + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + selectors: { + [`${rowLink}:hover &`]: { textDecoration: 'underline' }, + }, +}) + +export const txTag = style({ fontSize: '12px', color: vars.color.text3 }) + +export const amountIn = style({ fontSize: '13.5px', fontWeight: 600, color: '#0a7d55' }) +export const amountOut = style({ fontSize: '13.5px', fontWeight: 600, color: '#dc2626' }) + +export const time = style({ + fontSize: '12px', + color: vars.color.text3, + whiteSpace: 'nowrap', +}) + +export const viewAll = style({ + marginTop: '0.85rem', + fontSize: '13px', + color: vars.color.text3, + textAlign: 'center', + textDecoration: 'none', + selectors: { '&:hover': { color: vars.color.text1 } }, +}) + +export const empty = style({ + padding: '1.75rem 0', + textAlign: 'center', + color: vars.color.text3, + fontSize: '13px', +}) diff --git a/packages/dao-ui/src/components/Treasury/TreasuryRecentTransactions.tsx b/packages/dao-ui/src/components/Treasury/TreasuryRecentTransactions.tsx new file mode 100644 index 000000000..41ec8ec4b --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/TreasuryRecentTransactions.tsx @@ -0,0 +1,137 @@ +'use client' + +import { ETHERSCAN_BASE_URL } from '@buildeross/constants' +import { Auction_OrderBy, OrderDirection, SubgraphSDK } from '@buildeross/sdk/subgraph' +import { useChainStore, useDaoStore } from '@buildeross/stores' +import { formatTimeAgo } from '@buildeross/utils/formatTime' +import { formatCryptoVal } from '@buildeross/utils/numbers' +import { Box, Flex, Text } from '@buildeross/zord' +import { useMemo } from 'react' +import useSWR from 'swr' + +import { deriveRecentTransactions } from './recentTransactions.helper' +import * as styles from './TreasuryRecentTransactions.css' + +/** + * Treasury "Recent transactions" feed: executed proposals (ETH out, amount = + * sum of their tx values) and settled auctions (ETH in, the winning bid), + * merged newest-first from the Builder subgraph. Derivation lives in + * `recentTransactions.helper` (pure + unit-tested). + */ +export const TreasuryRecentTransactions = () => { + const chain = useChainStore((x) => x.chain) + const { addresses } = useDaoStore() + const token = addresses.token + const treasury = addresses.treasury + + // Query the subgraph directly — the getProposals helper resolves each + // proposal's on-chain state (an RPC call per proposal) and returns an empty + // list if any of those fail; we only need the subgraph fields here. + const { data: proposals } = useSWR( + token && chain.id ? (['treasury-recent-proposals', chain.id, token] as const) : null, + ([, chainId, t]) => + SubgraphSDK.connect(chainId) + .proposals({ where: { dao: t.toLowerCase() }, first: 100 }) + .then((d) => d.proposals), + { revalidateOnFocus: false } + ) + + const { data: auctions } = useSWR( + token && chain.id ? (['treasury-recent-auctions', chain.id, token] as const) : null, + ([, chainId, t]) => + SubgraphSDK.connect(chainId) + .auctionHistory({ + daoId: t.toLowerCase(), + startTime: 0, + orderBy: Auction_OrderBy.EndTime, + orderDirection: OrderDirection.Desc, + first: 20, + }) + .then((d) => d.dao?.auctions ?? []), + { revalidateOnFocus: false } + ) + + const txs = useMemo( + () => deriveRecentTransactions(proposals ?? [], auctions ?? [], 12), + [proposals, auctions] + ) + + const explorerUrl = ETHERSCAN_BASE_URL[chain.id] + + return ( + + + Recent transactions + + + + + Treasury activity + From proposals & auctions + + + {txs.length === 0 ? ( + No recent treasury activity. + ) : ( + txs.map((tx, i) => { + // No explorer for the local foundry chain — those rows stay unlinked. + const txUrl = + tx.txHash && explorerUrl ? `${explorerUrl}/tx/${tx.txHash}` : undefined + return ( + + + {tx.dir === 'in' ? '↓' : '↑'} + + +
{tx.title}
+
{tx.tag}
+
+ + {tx.dir === 'in' ? '+' : '−'} + {formatCryptoVal(tx.amountEth)} ETH + + {formatTimeAgo(tx.timestamp)} +
+ ) + }) + )} + + {treasury && explorerUrl && ( +
+ View all on explorer → + + )} + + + ) +} diff --git a/packages/dao-ui/src/components/Treasury/index.tsx b/packages/dao-ui/src/components/Treasury/index.tsx index 85c7a5707..2b60d1ddc 100644 --- a/packages/dao-ui/src/components/Treasury/index.tsx +++ b/packages/dao-ui/src/components/Treasury/index.tsx @@ -1 +1,4 @@ export * from './Treasury' +export * from './TreasuryAnalytics' +export * from './TreasuryComposition' +export * from './TreasuryNfts' diff --git a/packages/dao-ui/src/components/Treasury/recentTransactions.helper.test.ts b/packages/dao-ui/src/components/Treasury/recentTransactions.helper.test.ts new file mode 100644 index 000000000..93f09de06 --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/recentTransactions.helper.test.ts @@ -0,0 +1,121 @@ +import { describe, expect, it } from 'vitest' + +import { + type AuctionLike, + deriveRecentTransactions, + type ProposalLike, + sumProposalValuesEth, +} from './recentTransactions.helper' + +const eth = (n: number) => BigInt(Math.round(n * 1e6)) * 10n ** 12n // n ETH in wei + +describe('sumProposalValuesEth', () => { + it('sums per-transaction values into ETH (Prop 65: 1.37 + 2.75 = 4.12)', () => { + expect( + sumProposalValuesEth([eth(1.37).toString(), eth(2.75).toString()]) + ).toBeCloseTo(4.12, 6) + }) + it('returns 0 for empty / missing values', () => { + expect(sumProposalValuesEth([])).toBe(0) + expect(sumProposalValuesEth(null)).toBe(0) + }) +}) + +describe('deriveRecentTransactions', () => { + const proposals: ProposalLike[] = [ + { + proposalNumber: 65, + title: 'Tech Pod Residency Renewal', + values: [eth(1.37).toString(), eth(2.75).toString()], + executed: true, + executedAt: 3000, + executionTransactionHash: '0xabc', + }, + { + proposalNumber: 64, + title: '', + values: [eth(2.4).toString()], + executed: true, + executedAt: 1000, + }, + { + // not executed → excluded + proposalNumber: 66, + title: 'Pending', + values: [eth(9).toString()], + executed: false, + executedAt: null, + }, + ] + const auctions: AuctionLike[] = [ + { + id: '0xtoken:762', + endTime: 2000, + winningBid: { amount: eth(0.025).toString(), transactionHash: '0xbid762' }, + }, + { id: '0xtoken:761', endTime: 500, winningBid: { amount: '0' } }, // no bid → excluded + ] + + it('merges proposals (out) + auctions (in), newest-first', () => { + const rows = deriveRecentTransactions(proposals, auctions) + expect(rows.map((r) => r.dir)).toEqual(['out', 'in', 'out']) + expect(rows[0].tag).toBe('Prop #65') + expect(rows[1].title).toBe('Auction #762') + expect(rows[2].tag).toBe('Prop #64') + }) + + it('computes signed amounts and labels correctly', () => { + const [p65, a762, p64] = deriveRecentTransactions(proposals, auctions) + expect(p65.amountEth).toBeCloseTo(4.12, 6) + expect(p65.title).toBe('Tech Pod Residency Renewal') + expect(a762.amountEth).toBeCloseTo(0.025, 6) + expect(p64.title).toBe('Proposal 64') // empty title falls back + }) + + it('excludes non-executed proposals and no-bid auctions', () => { + const rows = deriveRecentTransactions(proposals, auctions) + expect(rows.find((r) => r.tag === 'Prop #66')).toBeUndefined() + expect(rows.find((r) => r.tag === 'Auction #761')).toBeUndefined() + }) + + it('excludes an executed:false proposal even if it carries a timestamp', () => { + const rows = deriveRecentTransactions( + [ + { + proposalNumber: 99, + values: [eth(5).toString()], + executed: false, + executedAt: 4000, + }, + ], + [] + ) + expect(rows).toHaveLength(0) + }) + + it('carries explorer tx hashes: execution hash for props, winning bid for auctions', () => { + const [p65, a762, p64] = deriveRecentTransactions(proposals, auctions) + expect(p65.txHash).toBe('0xabc') + expect(a762.txHash).toBe('0xbid762') + expect(p64.txHash).toBeUndefined() // no execution hash → row stays unlinked + }) + + it('leaves txHash undefined when an auction has no bid transaction hash', () => { + const [row] = deriveRecentTransactions( + [], + [{ id: '0xtoken:900', endTime: 10, winningBid: { amount: eth(1).toString() } }] + ) + expect(row.txHash).toBeUndefined() + }) + + it('caps to the limit', () => { + const many: ProposalLike[] = Array.from({ length: 20 }, (_, i) => ({ + proposalNumber: i + 1, + title: `P${i}`, + values: [eth(1).toString()], + executed: true, + executedAt: i + 1, + })) + expect(deriveRecentTransactions(many, [], 5)).toHaveLength(5) + }) +}) diff --git a/packages/dao-ui/src/components/Treasury/recentTransactions.helper.ts b/packages/dao-ui/src/components/Treasury/recentTransactions.helper.ts new file mode 100644 index 000000000..862f9a502 --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/recentTransactions.helper.ts @@ -0,0 +1,88 @@ +import { formatEther } from 'viem' + +export interface RecentTx { + dir: 'in' | 'out' + title: string + tag: string + amountEth: number + timestamp: number + txHash?: string +} + +export interface ProposalLike { + proposalNumber: number + title?: string | null + values?: readonly (string | bigint)[] | null + executed?: boolean | null + executedAt?: number | string | null + executionTransactionHash?: string | null +} + +export interface AuctionLike { + id: string + endTime: number | string + winningBid?: { amount?: string | null; transactionHash?: string | null } | null +} + +/** Sum a proposal's per-transaction `values` (ETH sent) into a single ETH amount. */ +export const sumProposalValuesEth = ( + values?: readonly (string | bigint)[] | null +): number => { + if (!values || values.length === 0) return 0 + try { + const total = values.reduce((sum, v) => sum + BigInt(v), 0n) + return Number(formatEther(total)) + } catch { + return 0 + } +} + +const auctionNumber = (id: string): string => id.split(':').pop() || '?' + +/** + * Build the treasury "Recent transactions" feed: executed proposals are ETH + * outflows (the amount is the sum of their tx `values`), settled auctions are + * inflows (the winning bid). Merged newest-first and capped. + */ +export const deriveRecentTransactions = ( + proposals: readonly ProposalLike[], + auctions: readonly AuctionLike[], + limit = 12 +): RecentTx[] => { + const proposalTxs: RecentTx[] = proposals + // Only executed proposals are outflows. `executedAt` is set iff a proposal + // executed, but guard on `executed` too (when the source provides it) so an + // `executed: false` record with a stray timestamp is never counted. + .filter((p) => !!p.executedAt && p.executed !== false) + .map((p) => ({ + dir: 'out', + title: p.title?.trim() || `Proposal ${p.proposalNumber}`, + tag: `Prop #${p.proposalNumber}`, + amountEth: sumProposalValuesEth(p.values), + timestamp: Number(p.executedAt), + txHash: p.executionTransactionHash ?? undefined, + })) + + const auctionTxs: RecentTx[] = auctions + .filter((a) => { + try { + return !!a.winningBid?.amount && BigInt(a.winningBid.amount) > 0n + } catch { + return false + } + }) + .map((a) => ({ + dir: 'in', + title: `Auction #${auctionNumber(a.id)}`, + tag: 'Auction settle', + amountEth: Number(formatEther(BigInt(a.winningBid!.amount!))), + timestamp: Number(a.endTime), + // The winning bid is the tx that moved this ETH; the subgraph exposes no + // settlement hash on `Auction` yet. + txHash: a.winningBid?.transactionHash ?? undefined, + })) + + return [...proposalTxs, ...auctionTxs] + .sort((a, b) => b.timestamp - a.timestamp) + .slice(0, limit) +} diff --git a/packages/dao-ui/src/components/Treasury/tokenLogos.ts b/packages/dao-ui/src/components/Treasury/tokenLogos.ts new file mode 100644 index 000000000..572033070 --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/tokenLogos.ts @@ -0,0 +1,24 @@ +/** + * Real brand logos for the well-known treasury tokens, embedded as base64 PNG + * data URIs (source: Trust Wallet assets, fetched by contract address) so the + * treasury composition renders correct token icons offline with no network or + * Alchemy metadata. Clanker / long-tail tokens fall back to their subgraph + * `tokenImage`, then to a lettered badge in the component. + * + * This file is generated data; the base64 strings are intentionally long. + */ + +/* eslint-disable */ +/* prettier-ignore */ +export const TOKEN_LOGOS: Record = { + ETH: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAMAAABlApw1AAACBFBMVEUAAADv7//09PTy8vXx9Pbz9Pjy9ffy9fjy9Pfx9Pfy9Pby9Pfx8/Xz8/Py8vTx9Pjv7/fy9Pfy9Pfy9ffz9ffy8/b09vjy9fXz9Pb09/ry9Pjz9fnv7/Tv9PTk5uiCg4Ssra9jZGWQkpTIycw7PDza296QkZIvMDBgYWK6vL21t7lHSUnm6OqEhojNz9Ly9PSztLednqB4envBw8Xv8vWen6Hv8/NsbW7x8/bP0NOpqqyJiovz8/dUVVXv7++lpqjy8/jz9Pbx9PZ9fn9bXF01NjYdHh4sLCw5Ojo0NTUwMTETExNucHBISElgYWE+Pz9zdHUaGhomJyfv7/oWFxckJSUtLi7x8vV4eXpRUlMhISHx8/Z1d3fy9PdnaGlERkaEhYZ6fHxrbW1AQUGDhYVWV1cqKipERUVOT1BcXV6LjI1iY2QyMzNMTU7Fx8lLTU2Sk5ba3N+HiIpKS0zW2Nt7fH4vLy+6vL6rrK6ChIXk5umfoKJYWVpXWVmQkpPd3+GTlJaXmJnOz9Lm5+qFhoepq6y6u77r7fB1dneRkpQ7PT2EhoeQkZPIysxISUnW2NrW19uztLa3uLqXmJp4enpTVVVvcHKsrrBmZ2g8PT2eoKJsbm+en6A9PT7v8/dsbm7BwsXd3+KEhYfx8/fy9fbP0dPx9Pjx8/bv8veJiozy9fnv8vQEFD2BAAAArHRSTlMAEDBQcI+fr7/f7/+AQGDPIJ9g33+vb1CPX+9/MDD//////////////////////2D/////UP9A/5D///9A/xD/r8/P/////////////////////zD///+g////sP/f/////////////////////////////////////////////////////////////////////////////////////0D/////gK//cO9g/1BgIk4dsgAACKdJREFUeNrM1YV1wEAMA9BjsMJOGfYfszBA0YnyJ5De6fmcPR9iyqW23gWfpPfWypBi8O7afEi5Cb4gLafxouGnPOOH5hyXa4Ufc8cvzWu8SvrUBH9Tt4U/nIZ/aZt3PGMW/JusI206MKIbIf4uMKTr4s60ZIG1EyssKwwYVGCMh19hFxxI09GHU3EwjUeu5wYGeDu6FRig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', + WETH: 'data:image/png;base64,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', + USDC: 'data:image/png;base64,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', + USDT: 'data:image/png;base64,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', + DAI: 'data:image/png;base64,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', + HIGHER: 'data:image/png;base64,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DA+rz/wDShXAAUAAds+yILjL/vc5OpK4v8nrPn9UlpkqgOWFS6krANPZpgUh0UQRweBe3c5QUCAoSgyKXDpbN3WE6pKwrFQBLCeCmmh90kbiIkbFraEDEhFQQQjR7c2CBcpg/ZnqQBFRNF7ApHMNy+oo27vULc8E4gqAKoBlh0ydxWU3XbFFm9txGuQ2hREMIhixa2/8IAgwwUQTREXDEceLqbv6lr9Ta4BDXbX/ZYTpXfMH+z0cVhQvajJGwkimgXVmMoFBhQUAD/Yxovv9YF9HUywAWJgBFGTIVmQTDIGBMbsVq8HQZaSuAMuMlZJccnCVq4TNe/S+OwULC6SwqSe/pwT6bym5gkAIMgqQBmb0QY6xcpFq2HqZqQJYZpKatDODTk/jomJJ/RFPhYkQFf5gZ+JEAGEEZBILCMkKLKMNI9GZ8kM8UFd5aFQBLDOChTWyJFKNlWkaCxRNBJD34sBwSQSCDBDMPIOTSdfawKCicU1dLi9VAMtMsESSEMHemPsApgxMESKKdQ92qpOQhyhmY9BABBgAB+iU+/Dowb6/w40qgGWGgAWCYb29Sv121hUURGTb26GIFKCiCRZKZACATets+tqCKoFlpQpgmQlaoQGg0K8BAWPvCBkCFntN6gZhBCRRAgQTKEK0LBkLVfcAy0kVwLJDcVr6RYAEpELIGIQo0/0jQHuSCfZWD1qfQAMBas8Ec2X5qAJYZigZRASnxcEAxP5LgoD1x6Qf5McFAwWIIqcuDwM0cW+6qTxSqgCWHwq94152nemfbgN2ffugD3OflhRTQLlfFXy1/gNADapVZpoqgMpMUwVQmWmqACozTRVAZaapAqjMNFUAlZmmCqAy01QBVGaaKoDKTFMFUJlpqgAqM00VQGWmqQKozDRVAJWZpgqgMtNUAVRmmiqAykxTBVCZaaoAKjNNFUBlpqkCqMw0VQCVmaYKoDLTVAFUZpoqgMpMUwVQmWmqACozTRVAZaapAqjMNFUAlZmmCqAy01QBVGaaKoDKTFMFUJlpqgAqM00VQGWmqQKozDRVAJWZpgqgMtNUAVRmmiqAykxTBVCZaaoAKjNNFUBlpqkCqMw0VQCVmaYKoDLTVAFUZpoqgMpM8/8DQNcYM1hifLAAAAAldEVYdGRhdGU6Y3JlYXRlADIwMjQtMDQtMDdUMTc6MzI6MzMrMDM6MDCUFePnAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDI0LTA0LTA3VDE3OjMyOjMzKzAzOjAw5UhbWwAAACZ0RVh0aWNjOmNvcHlyaWdodABObyBjb3B5cmlnaHQsIHVzZSBmcmVlbHmnmvCCAAAAHXRFWHRpY2M6ZGVzY3JpcHRpb24Ac1JHQiBidWlsdC1pbuOFycUAAAAedEVYdGljYzptYW51ZmFjdHVyZXIAc1JHQiBidWlsdC1pbk8YSRsAAAAXdEVYdGljYzptb2RlbABzUkdCIGJ1aWx0LWluzZAmhQAAAABJRU5ErkJggg==', +} + +/** Local logo data-URI for a known token symbol, or undefined. */ +export const tokenLogo = (symbol: string): string | undefined => + TOKEN_LOGOS[symbol.toUpperCase()] diff --git a/packages/dao-ui/src/components/Treasury/treasuryAnalytics.helper.test.ts b/packages/dao-ui/src/components/Treasury/treasuryAnalytics.helper.test.ts new file mode 100644 index 000000000..b08b13bc4 --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/treasuryAnalytics.helper.test.ts @@ -0,0 +1,103 @@ +import { parseEther } from 'viem' +import { describe, expect, it } from 'vitest' + +import { + type AuctionDatum, + buildChartPaths, + buildYTicks, + computeCumulativeRevenue, + computeTreasuryMetrics, +} from './treasuryAnalytics.helper' + +const wei = (eth: string) => parseEther(eth).toString() + +const data: AuctionDatum[] = [ + { id: '2', endTime: 200, winningBidAmt: wei('2') }, + { id: '1', endTime: 100, winningBidAmt: wei('1') }, + { id: '3', endTime: 300, winningBidAmt: wei('0.5') }, +] + +describe('computeTreasuryMetrics', () => { + it('aggregates revenue, count, average and highest sale', () => { + const m = computeTreasuryMetrics(data) + expect(m.totalRevenue).toBeCloseTo(3.5) + expect(m.auctionsSettled).toBe(3) + expect(m.averageWinningBid).toBeCloseTo(3.5 / 3) + expect(m.highestSale).toBeCloseTo(2) + }) + + it('returns zeros for an empty window', () => { + expect(computeTreasuryMetrics([])).toEqual({ + totalRevenue: 0, + auctionsSettled: 0, + averageWinningBid: 0, + highestSale: 0, + }) + }) + + it('treats malformed wei amounts as zero', () => { + const m = computeTreasuryMetrics([{ id: 'x', endTime: 1, winningBidAmt: 'nope' }]) + expect(m.totalRevenue).toBe(0) + expect(m.auctionsSettled).toBe(1) + }) + + it('excludes no-bid (burned) auctions from the average, not the count', () => { + const withBurns: AuctionDatum[] = [ + { id: '1', endTime: 100, winningBidAmt: wei('1') }, + { id: '2', endTime: 200, winningBidAmt: wei('3') }, + { id: '3', endTime: 300, winningBidAmt: '0' }, // no bids, NFT burned + { id: '4', endTime: 400, winningBidAmt: '0' }, // no bids, NFT burned + ] + const m = computeTreasuryMetrics(withBurns) + expect(m.totalRevenue).toBeCloseTo(4) + expect(m.auctionsSettled).toBe(4) // count still reflects all settled auctions + expect(m.averageWinningBid).toBeCloseTo(2) // 4 / 2 bidded, not 4 / 4 + }) +}) + +describe('computeCumulativeRevenue', () => { + it('sorts ascending by endTime and accumulates', () => { + const series = computeCumulativeRevenue(data) + expect(series.map((p) => p.endTime)).toEqual([100, 200, 300]) + expect(series.map((p) => Number(p.cumulative.toFixed(2)))).toEqual([1, 3, 3.5]) + }) + + it('does not mutate the input array', () => { + const input = [...data] + computeCumulativeRevenue(input) + expect(input.map((d) => d.id)).toEqual(['2', '1', '3']) + }) +}) + +describe('buildChartPaths', () => { + it('returns empty paths for fewer than two points', () => { + expect(buildChartPaths([{ endTime: 1, cumulative: 1 }], 100, 50)).toEqual({ + linePath: '', + areaPath: '', + }) + }) + + it('anchors the first point at x=0 and the last at x=width', () => { + const series = computeCumulativeRevenue(data) + const { linePath, areaPath } = buildChartPaths(series, 300, 100) + expect(linePath.startsWith('M 0.00')).toBe(true) + expect(linePath).toContain('L 300.00') + // area path closes back down to the baseline (y = height) and Z-closes + expect(areaPath.endsWith('Z')).toBe(true) + expect(areaPath).toContain('100') + }) +}) + +describe('buildYTicks', () => { + it('returns divisions+1 ticks spanning 0..maxY inclusive', () => { + const ticks = buildYTicks(10, 4) + expect(ticks.map((t) => t.value)).toEqual([0, 2.5, 5, 7.5, 10]) + expect(ticks.map((t) => t.fraction)).toEqual([0, 0.25, 0.5, 0.75, 1]) + }) + + it('handles a zero max', () => { + const ticks = buildYTicks(0, 4) + expect(ticks.every((t) => t.value === 0)).toBe(true) + expect(ticks).toHaveLength(5) + }) +}) diff --git a/packages/dao-ui/src/components/Treasury/treasuryAnalytics.helper.ts b/packages/dao-ui/src/components/Treasury/treasuryAnalytics.helper.ts new file mode 100644 index 000000000..21656ba5b --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/treasuryAnalytics.helper.ts @@ -0,0 +1,127 @@ +import { formatEther } from 'viem' + +/** A settled auction datum as returned by the /api/auctionHistory endpoint. */ +export interface AuctionDatum { + id: string + /** Auction end time, unix seconds. */ + endTime: number + /** Winning bid amount, wei (string). */ + winningBidAmt: string +} + +export interface TreasuryMetrics { + /** Sum of all winning bids in the window, in ETH. */ + totalRevenue: number + /** Count of settled auctions in the window. */ + auctionsSettled: number + /** Mean winning bid in the window, in ETH (0 when none). */ + averageWinningBid: number + /** Largest single winning bid in the window, in ETH. */ + highestSale: number +} + +/** A point on the cumulative-revenue series. */ +export interface RevenuePoint { + endTime: number + /** Cumulative ETH revenue up to and including this auction. */ + cumulative: number +} + +const toEth = (wei: string): number => { + try { + return Number(formatEther(BigInt(wei))) + } catch { + return 0 + } +} + +/** Aggregate headline treasury metrics from settled auctions. */ +export const computeTreasuryMetrics = (data: AuctionDatum[]): TreasuryMetrics => { + if (!data.length) { + return { totalRevenue: 0, auctionsSettled: 0, averageWinningBid: 0, highestSale: 0 } + } + + const amounts = data.map((d) => toEth(d.winningBidAmt)) + const totalRevenue = amounts.reduce((sum, v) => sum + v, 0) + const auctionsSettled = data.length + + // Auctions with no bids are settled with the NFT burned (winningBid = null, + // coerced to 0). Exclude them from the average so the "winning bid" mean + // reflects auctions that actually sold, not the burn count. + const winningAmounts = amounts.filter((v) => v > 0) + + return { + totalRevenue, + auctionsSettled, + averageWinningBid: winningAmounts.length ? totalRevenue / winningAmounts.length : 0, + highestSale: Math.max(...amounts), + } +} + +/** Build the cumulative-revenue time series, sorted ascending by endTime. */ +export const computeCumulativeRevenue = (data: AuctionDatum[]): RevenuePoint[] => { + const sorted = [...data].sort((a, b) => a.endTime - b.endTime) + let running = 0 + return sorted.map((d) => { + running += toEth(d.winningBidAmt) + return { endTime: d.endTime, cumulative: running } + }) +} + +export interface ChartPaths { + /** SVG path for the revenue line. */ + linePath: string + /** SVG path for the filled area beneath the line. */ + areaPath: string +} + +/** + * Map a cumulative-revenue series to SVG path strings within a + * `width` x `height` viewBox. Pure — no DOM, deterministic for a given input. + */ +export const buildChartPaths = ( + points: RevenuePoint[], + width: number, + height: number +): ChartPaths => { + if (points.length < 2) return { linePath: '', areaPath: '' } + + const xs = points.map((p) => p.endTime) + const minX = Math.min(...xs) + const maxX = Math.max(...xs) + const maxY = Math.max(...points.map((p) => p.cumulative)) + + const spanX = maxX - minX || 1 + const spanY = maxY || 1 + + const coords = points.map((p) => ({ + x: ((p.endTime - minX) / spanX) * width, + y: height - (p.cumulative / spanY) * height, + })) + + const linePath = coords + .map((c, i) => `${i === 0 ? 'M' : 'L'} ${c.x.toFixed(2)} ${c.y.toFixed(2)}`) + .join(' ') + + const first = coords[0] + const last = coords[coords.length - 1] + const areaPath = `${linePath} L ${last.x.toFixed(2)} ${height} L ${first.x.toFixed(2)} ${height} Z` + + return { linePath, areaPath } +} + +export interface YTick { + /** Value at this tick, in ETH. */ + value: number + /** Position from the baseline, 0 (bottom) → 1 (top). */ + fraction: number +} + +/** Evenly spaced Y-axis ticks from 0 up to `maxY`, inclusive of both ends. */ +export const buildYTicks = (maxY: number, divisions = 4): YTick[] => { + const steps = Math.max(1, Math.floor(divisions)) + return Array.from({ length: steps + 1 }, (_, i) => { + const fraction = i / steps + return { value: maxY * fraction, fraction } + }) +} diff --git a/packages/dao-ui/src/components/Treasury/treasuryComposition.helper.test.ts b/packages/dao-ui/src/components/Treasury/treasuryComposition.helper.test.ts new file mode 100644 index 000000000..9cb7c4da1 --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/treasuryComposition.helper.test.ts @@ -0,0 +1,71 @@ +import { parseEther, parseUnits } from 'viem' +import { describe, expect, it } from 'vitest' + +import { + computeDonutArcs, + formatTokenAmount, + formatUsd, + sliceColor, + tokenUsdValue, +} from './treasuryComposition.helper' + +describe('tokenUsdValue', () => { + it('values stables 1:1', () => { + expect(tokenUsdValue(parseUnits('1500', 6), 6, 'stable', 3000)).toBeCloseTo(1500) + }) + + it('values WETH at the ETH price', () => { + expect(tokenUsdValue(parseEther('2'), 18, 'weth', 3000)).toBeCloseTo(6000) + }) + + it('values other tokens at 0 (balance-only)', () => { + expect(tokenUsdValue(parseEther('999'), 18, 'other', 3000)).toBe(0) + }) +}) + +describe('formatUsd', () => { + it('compacts thousands and millions', () => { + expect(formatUsd(1234)).toBe('$1.2k') + expect(formatUsd(2_500_000)).toBe('$2.5M') + expect(formatUsd(42)).toBe('$42') + }) +}) + +describe('formatTokenAmount', () => { + it('formats whole and fractional amounts, trimming zeros', () => { + expect(formatTokenAmount(parseUnits('13381.55', 6), 6)).toBe('13,381.55') + expect(formatTokenAmount(parseEther('0.0282'), 18)).toBe('0.0282') + expect(formatTokenAmount(0n, 18)).toBe('0') + }) +}) + +describe('computeDonutArcs', () => { + it('produces arcs that tile the ring in order without gaps', () => { + const C = 100 + const arcs = computeDonutArcs( + [ + { name: 'A', color: '#000', value: 1 }, + { name: 'B', color: '#111', value: 3 }, + ], + C + ) + // A = 25% => len 25 at offset 0; B = 75% => len 75 at offset -25 + expect(arcs[0].dashArray).toBe('25.000 75.000') + expect(arcs[0].dashOffset).toBe(0) + expect(arcs[1].dashArray).toBe('75.000 25.000') + expect(arcs[1].dashOffset).toBe(-25) + }) + + it('handles an all-zero total without dividing by zero', () => { + const arcs = computeDonutArcs([{ name: 'A', color: '#000', value: 0 }], 100) + expect(arcs[0].dashArray).toBe('0.000 100.000') + }) +}) + +describe('sliceColor', () => { + it('uses known colors and falls back for unknowns', () => { + expect(sliceColor('USDC', 0)).toBe('#2ecc8f') + expect(sliceColor('WETH', 1)).toBe('#9a9aa2') + expect(sliceColor('RANDOM', 0)).toBe('#ffb347') + }) +}) diff --git a/packages/dao-ui/src/components/Treasury/treasuryComposition.helper.ts b/packages/dao-ui/src/components/Treasury/treasuryComposition.helper.ts new file mode 100644 index 000000000..e0609182f --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/treasuryComposition.helper.ts @@ -0,0 +1,94 @@ +import { formatUnits } from 'viem' + +import type { TokenKind } from './treasuryTokens' + +/** + * USD value of a token balance. Prices are derived, not fetched per-token: + * - stables → 1:1 with USD + * - WETH → balance × ETH/USD price + * - other → 0 (shown with a balance, but excluded from the USD total/donut) + * This keeps valuation dependency-free and can't fail on long-tail tokens. + */ +export const tokenUsdValue = ( + balanceRaw: bigint, + decimals: number, + kind: TokenKind, + ethUsdPrice: number +): number => { + const human = Number(formatUnits(balanceRaw, decimals)) + if (kind === 'stable') return human + if (kind === 'weth') return human * ethUsdPrice + return 0 +} + +/** Compact USD, e.g. $1.2k / $3.4M. */ +export const formatUsd = (n: number): string => { + if (n >= 1_000_000) return `$${(n / 1_000_000).toFixed(1)}M` + if (n >= 1_000) return `$${(n / 1_000).toFixed(1)}k` + return `$${n.toLocaleString('en-US', { maximumFractionDigits: 0 })}` +} + +/** Human token amount, up to 4 fractional digits, trailing zeros trimmed. */ +export const formatTokenAmount = (raw: bigint, decimals: number): string => { + if (raw === 0n) return '0' + const base = 10n ** BigInt(decimals) + const whole = raw / base + const fraction = raw % base + if (fraction === 0n) return whole.toLocaleString('en-US') + const fracStr = fraction + .toString() + .padStart(decimals, '0') + .slice(0, 4) + .replace(/0+$/, '') + return fracStr + ? `${whole.toLocaleString('en-US')}.${fracStr}` + : whole.toLocaleString('en-US') +} + +export interface DonutSlice { + name: string + color: string + value: number +} + +export interface DonutArc { + /** stroke-dasharray "len gap" for this slice. */ + dashArray: string + /** negative offset positioning this slice after the previous ones. */ + dashOffset: number +} + +/** + * Map slice values to SVG circle stroke-dasharray/offset arcs around a ring of + * circumference `circumference`. Pure — deterministic for a given input. + */ +export const computeDonutArcs = ( + slices: DonutSlice[], + circumference: number +): DonutArc[] => { + const total = slices.reduce((s, x) => s + x.value, 0) + let offset = 0 + return slices.map((s) => { + const len = total > 0 ? (s.value / total) * circumference : 0 + const arc: DonutArc = { + dashArray: `${len.toFixed(3)} ${(circumference - len).toFixed(3)}`, + dashOffset: offset === 0 ? 0 : -offset, + } + offset += len + return arc + }) +} + +const SLICE_COLORS: Record = { + ETH: '#5b8def', + WETH: '#9a9aa2', + USDC: '#2ecc8f', + USDT: '#26a17b', + DAI: '#f4b731', +} +const FALLBACK_COLORS = ['#ffb347', '#c084fc', '#f472b6', '#34d399', '#60a5fa'] + +/** Stable color for a token symbol, falling back to a rotating palette. */ +export const sliceColor = (symbol: string, fallbackIndex: number): string => + SLICE_COLORS[symbol.toUpperCase()] ?? + FALLBACK_COLORS[fallbackIndex % FALLBACK_COLORS.length] diff --git a/packages/dao-ui/src/components/Treasury/treasuryTokens.ts b/packages/dao-ui/src/components/Treasury/treasuryTokens.ts new file mode 100644 index 000000000..df2ba8906 --- /dev/null +++ b/packages/dao-ui/src/components/Treasury/treasuryTokens.ts @@ -0,0 +1,106 @@ +import { CHAIN_ID } from '@buildeross/types' + +/** + * Global, per-CHAIN registry of well-known treasury tokens. + * + * This is intentionally keyed by chain (a handful of entries), NOT by DAO — + * so it scales to every DAO on the platform with zero per-DAO configuration. + * Each DAO's own clanker token is discovered dynamically from the subgraph and + * appended at runtime (see TreasuryComposition), so this list only needs the + * chain-level blue-chips (stables, wrapped ETH, notable community tokens). + */ +export type TokenKind = 'stable' | 'weth' | 'other' + +export interface TreasuryToken { + symbol: string + address: `0x${string}` + decimals: number + kind: TokenKind +} + +export const COMMON_TREASURY_TOKENS: Partial> = { + [CHAIN_ID.BASE]: [ + { + symbol: 'USDC', + address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', + decimals: 6, + kind: 'stable', + }, + { + symbol: 'USDT', + address: '0xfde4c96c8593536e31f229ea8f37b2ada2699bb2', + decimals: 6, + kind: 'stable', + }, + { + symbol: 'DAI', + address: '0x50c5725949a6f0c72e6c4a641f24049a917db0cb', + decimals: 18, + kind: 'stable', + }, + { + symbol: 'WETH', + address: '0x4200000000000000000000000000000000000006', + decimals: 18, + kind: 'weth', + }, + { + symbol: 'HIGHER', + address: '0x0578d8a44db98b23bf096a382e016e29a5ce0ffe', + decimals: 18, + kind: 'other', + }, + ], + [CHAIN_ID.ETHEREUM]: [ + { + symbol: 'USDC', + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + decimals: 6, + kind: 'stable', + }, + { + symbol: 'USDT', + address: '0xdac17f958d2ee523a2206206994597c13d831ec7', + decimals: 6, + kind: 'stable', + }, + { + symbol: 'DAI', + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + decimals: 18, + kind: 'stable', + }, + { + symbol: 'WETH', + address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + decimals: 18, + kind: 'weth', + }, + ], + [CHAIN_ID.OPTIMISM]: [ + { + symbol: 'USDC', + address: '0x0b2c639c533813f4aa9d7837caf62653d097ff85', + decimals: 6, + kind: 'stable', + }, + { + symbol: 'USDT', + address: '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58', + decimals: 6, + kind: 'stable', + }, + { + symbol: 'DAI', + address: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + decimals: 18, + kind: 'stable', + }, + { + symbol: 'WETH', + address: '0x4200000000000000000000000000000000000006', + decimals: 18, + kind: 'weth', + }, + ], +} diff --git a/packages/sdk/src/subgraph/queries/auctionHistory.graphql b/packages/sdk/src/subgraph/queries/auctionHistory.graphql index c9dea5242..be075c6b6 100644 --- a/packages/sdk/src/subgraph/queries/auctionHistory.graphql +++ b/packages/sdk/src/subgraph/queries/auctionHistory.graphql @@ -16,6 +16,7 @@ query auctionHistory( endTime winningBid { amount + transactionHash } settled } diff --git a/packages/sdk/src/subgraph/sdk.generated.ts b/packages/sdk/src/subgraph/sdk.generated.ts index 863e581a0..8401358d5 100644 --- a/packages/sdk/src/subgraph/sdk.generated.ts +++ b/packages/sdk/src/subgraph/sdk.generated.ts @@ -11585,7 +11585,11 @@ export type AuctionHistoryQuery = { id: string endTime: any settled: boolean - winningBid?: { __typename?: 'AuctionBid'; amount: any } | null + winningBid?: { + __typename?: 'AuctionBid' + amount: any + transactionHash: any + } | null }> } | null } @@ -14186,6 +14190,7 @@ export const AuctionHistoryDocument = gql` endTime winningBid { amount + transactionHash } settled }