Skip to content

Commit 0abac11

Browse files
ci(release): publish latest release
1 parent fb39602 commit 0abac11

20 files changed

Lines changed: 703 additions & 166 deletions

RELEASE

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
IPFS hash of the deployment:
2-
- CIDv0: `QmPjuGM1wsScvkB1LSBa22Fm61tgEQ8qRVoimnXCxkuNfG`
3-
- CIDv1: `bafybeiau2cap5oub3nn6jg6u4qdl7ftf3az7bof3b5mu26xiy2l326q4r4`
2+
- CIDv0: `Qma941FXDbQqHNpD7hkUYG1PrK3s6vmuimRLL9M8p5tm3Z`
3+
- CIDv1: `bafybeifpkoosgylgtfnzobmelsuj6wjfwlpzwy5mg2jilplofd5tmxtfdq`
44

55
The latest release is always mirrored at [app.uniswap.org](https://app.uniswap.org).
66

@@ -10,5 +10,5 @@ You can also access the Uniswap Interface from an IPFS gateway.
1010
Your Uniswap settings are never remembered across different URLs.
1111

1212
IPFS gateways:
13-
- https://bafybeiau2cap5oub3nn6jg6u4qdl7ftf3az7bof3b5mu26xiy2l326q4r4.ipfs.dweb.link/
14-
- [ipfs://QmPjuGM1wsScvkB1LSBa22Fm61tgEQ8qRVoimnXCxkuNfG/](ipfs://QmPjuGM1wsScvkB1LSBa22Fm61tgEQ8qRVoimnXCxkuNfG/)
13+
- https://bafybeifpkoosgylgtfnzobmelsuj6wjfwlpzwy5mg2jilplofd5tmxtfdq.ipfs.dweb.link/
14+
- [ipfs://Qma941FXDbQqHNpD7hkUYG1PrK3s6vmuimRLL9M8p5tm3Z/](ipfs://Qma941FXDbQqHNpD7hkUYG1PrK3s6vmuimRLL9M8p5tm3Z/)

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
web/5.151.2
1+
web/5.151.3

apps/web/src/features/Toucan/Auction/AuctionHeader.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { BreadcrumbNavContainer, BreadcrumbNavLink, CurrentPageBreadcrumb } from
1616
import { HEADER_TRANSITION } from '~/components/StickyCollapsibleHeader/constants'
1717
import { getHeaderLogoSize, getHeaderTitleVariant } from '~/components/StickyCollapsibleHeader/getHeaderLogoSize'
1818
import { MouseoverTooltip, TooltipSize } from '~/components/Tooltip'
19+
import { useAuctionRedemption } from '~/features/Toucan/Auction/hooks/useAuctionRedemption'
1920
import { useAuctionStore } from '~/features/Toucan/Auction/store/useAuctionStore'
2021
import { EllipsisTamaguiStyle } from '~/theme/components/styles'
2122

@@ -126,6 +127,9 @@ const AuctionTokenInfo = ({
126127

127128
export const AuctionHeader = ({ isCompact = false }: { isCompact?: boolean }) => {
128129
const auctionDetails = useAuctionStore((state) => state.auctionDetails)
130+
// For redeemable virtual-token auctions, link the token name/logo to the real token — consistent
131+
// with the token-launched banner (both resolve through useAuctionRedemption).
132+
const { isRedeemable, realTokenAddress } = useAuctionRedemption()
129133

130134
const verifiedAuctionIds: string[] = useDynamicConfigValue({
131135
config: DynamicConfigs.VerifiedAuctions,
@@ -147,10 +151,10 @@ export const AuctionHeader = ({ isCompact = false }: { isCompact?: boolean }) =>
147151
}
148152
const chainInfo = getChainInfo(auctionDetails.chainId)
149153
return getTokenDetailsURL({
150-
address: auctionDetails.tokenAddress,
154+
address: isRedeemable && realTokenAddress ? realTokenAddress : auctionDetails.tokenAddress,
151155
chainUrlParam: chainInfo.urlParam,
152156
})
153-
}, [auctionDetails])
157+
}, [auctionDetails, isRedeemable, realTokenAddress])
154158

155159
if (!auctionDetails) {
156160
return null

apps/web/src/features/Toucan/Auction/Banners/TokenLaunched/TokenLaunchedBanner.tsx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import { TokenLaunchedBannerInner } from '~/features/Toucan/Auction/Banners/Toke
88
import { TokenLaunchedBannerSkeleton } from '~/features/Toucan/Auction/Banners/TokenLaunched/TokenLaunchedBannerSkeleton'
99
import { TokenLaunchFailedBannerContent } from '~/features/Toucan/Auction/Banners/TokenLaunched/TokenLaunchFailedBannerContent'
1010
import { TokenRestrictedBannerContent } from '~/features/Toucan/Auction/Banners/TokenLaunched/TokenRestrictedBannerContent'
11+
import { useRealTokenMarketInfo } from '~/features/Toucan/Auction/Banners/TokenLaunched/useRealTokenMarketInfo'
1112
import { useTokenLaunchedBannerColorData } from '~/features/Toucan/Auction/Banners/TokenLaunched/useTokenLaunchedBannerColorData'
1213
import { useTokenLaunchedBannerPriceData } from '~/features/Toucan/Auction/Banners/TokenLaunched/useTokenLaunchedBannerPriceData'
1314
import { fromQ96ToDecimalWithTokenDecimals } from '~/features/Toucan/Auction/BidDistributionChart/utils/q96'
15+
import { useAuctionRedemption } from '~/features/Toucan/Auction/hooks/useAuctionRedemption'
1416
import { useBidTokenInfo } from '~/features/Toucan/Auction/hooks/useBidTokenInfo'
1517
import { useDurationRemaining } from '~/features/Toucan/Auction/hooks/useDurationRemaining'
1618
import { useAuctionStore } from '~/features/Toucan/Auction/store/useAuctionStore'
@@ -62,6 +64,16 @@ export function TokenLaunchedBanner({
6264
tokenAddress && chainId && getAuctionMetadata({ chainId, tokenAddress })?.tradingRestrictedUntilTge,
6365
)
6466

67+
// Redeemable virtual-token auctions present the REAL (underlying) token instead: its price/chart,
68+
// name, FDV, and TDP link. The real token address is read on-chain (gated by a config override).
69+
const { isRedeemable, realTokenAddress, loading: redemptionLoading } = useAuctionRedemption()
70+
const priceTokenAddress = isRedeemable ? realTokenAddress : tokenAddress
71+
const {
72+
fdvUsd: realTokenFdvUsd,
73+
name: realTokenName,
74+
loading: realTokenInfoLoading,
75+
} = useRealTokenMarketInfo({ tokenAddress: realTokenAddress, chainId, skip: !isRedeemable })
76+
6577
const { bannerGradient, accentColor } = useTokenLaunchedBannerColorData({
6678
tokenColor: isGraduated ? tokenColor : colors.statusCritical.val,
6779
tokenColorLoading,
@@ -74,9 +86,9 @@ export function TokenLaunchedBanner({
7486
loading: priceLoading,
7587
error: priceError,
7688
} = useTokenLaunchedBannerPriceData({
77-
tokenAddress,
89+
tokenAddress: priceTokenAddress,
7890
chainId,
79-
skip: !isGraduated || tradingRestrictedUntilTge || !tokenAddress || !chainId,
91+
skip: !isGraduated || tradingRestrictedUntilTge || !priceTokenAddress || !chainId,
8092
})
8193

8294
// Fetch bid token info (needed for clearing price fallback conversion to USD)
@@ -162,14 +174,19 @@ export function TokenLaunchedBanner({
162174
}
163175

164176
// Show loading skeleton while data is being fetched
165-
const isLoading = priceLoading || bidTokenLoading || (needsFallback && clearingHistoryLoading)
177+
const isLoading =
178+
priceLoading ||
179+
bidTokenLoading ||
180+
(needsFallback && clearingHistoryLoading) ||
181+
(isRedeemable && (redemptionLoading || realTokenInfoLoading))
166182
if (isLoading) {
167183
return <TokenLaunchedBannerSkeleton />
168184
}
169185

170186
// Don't render a tradeable banner if no data is available (neither primary nor fallback).
171187
// Pre-trade banners should still render because their purpose is status, not price discovery.
172-
if (isTradeAvailable && !effectivePriceData) {
188+
// Redeem banners also always render — they carry the real token's FDV + link, not a price chart.
189+
if (isTradeAvailable && !effectivePriceData && !isRedeemable) {
173190
logger.warn('TokenLaunchedBanner', 'TokenLaunchedBanner', 'No price data available (primary or fallback)', {
174191
hasPriceData: !!priceData,
175192
hasFallbackPriceData: !!fallbackPriceData,
@@ -185,7 +202,7 @@ export function TokenLaunchedBanner({
185202
// Show success state with price data
186203
return (
187204
<TokenLaunchedBannerInner
188-
tokenName={tokenName}
205+
tokenName={isRedeemable ? (realTokenName ?? tokenName) : tokenName}
189206
tokenColor={tokenColor}
190207
totalSupply={totalSupply}
191208
auctionTokenDecimals={auctionTokenDecimals}
@@ -201,6 +218,8 @@ export function TokenLaunchedBanner({
201218
}
202219
bannerGradient={bannerGradient}
203220
accentColor={accentColor}
221+
fdvUsdOverride={isRedeemable ? (realTokenFdvUsd ?? null) : undefined}
222+
tokenDetailsAddress={isRedeemable ? realTokenAddress : undefined}
204223
/>
205224
)
206225
}

apps/web/src/features/Toucan/Auction/Banners/TokenLaunched/TokenLaunchedBannerContent.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ interface TokenLaunchedBannerContentProps {
2121
currentTickValue?: number
2222
isTradeAvailable: boolean
2323
tradeAvailabilityDurationRemaining: string | undefined
24+
// Redeemable virtual tokens display the real token's FDV from indexed market data rather than
25+
// computing it from currentTickValue x totalSupply (which would use the virtual token's supply).
26+
// `number` → show it; `null` → redeem mode but FDV unavailable, show "--"; `undefined` → compute.
27+
fdvUsdOverride?: number | null
28+
// TDP address for the "Trade now" link. Defaults to the auctioned token; set to the real token
29+
// when the auctioned token is a redeemable virtual token.
30+
tokenDetailsAddress?: string
2431
}
2532

2633
export function TokenLaunchedBannerContent({
@@ -31,13 +38,18 @@ export function TokenLaunchedBannerContent({
3138
currentTickValue,
3239
isTradeAvailable,
3340
tradeAvailabilityDurationRemaining,
41+
fdvUsdOverride,
42+
tokenDetailsAddress,
3443
}: TokenLaunchedBannerContentProps) {
3544
const { t } = useTranslation()
3645
const { convertFiatAmountFormatted } = useLocalizationContext()
3746
const navigate = useNavigate()
3847
const auctionDetails = useAuctionStore((state) => state.auctionDetails)
3948

4049
const displayValue = useMemo(() => {
50+
if (fdvUsdOverride !== undefined) {
51+
return fdvUsdOverride === null ? '--' : convertFiatAmountFormatted(fdvUsdOverride, NumberType.FiatTokenStats)
52+
}
4153
if (currentTickValue === undefined) {
4254
return '--'
4355
}
@@ -57,18 +69,18 @@ export function TokenLaunchedBannerContent({
5769
}
5870

5971
return convertFiatAmountFormatted(currentFdvUsd, NumberType.FiatTokenStats)
60-
}, [auctionTokenDecimals, convertFiatAmountFormatted, currentTickValue, totalSupply])
72+
}, [auctionTokenDecimals, convertFiatAmountFormatted, currentTickValue, fdvUsdOverride, totalSupply])
6173

6274
const onPress = useCallback(() => {
6375
if (!auctionDetails) {
6476
return
6577
}
6678
const tokenDetailsURL = getTokenDetailsURL({
67-
address: auctionDetails.tokenAddress,
79+
address: tokenDetailsAddress ?? auctionDetails.tokenAddress,
6880
chain: toGraphQLChain(auctionDetails.chainId),
6981
})
7082
navigate(tokenDetailsURL)
71-
}, [auctionDetails, navigate])
83+
}, [auctionDetails, navigate, tokenDetailsAddress])
7284

7385
const canPress = Boolean(auctionDetails && isTradeAvailable)
7486
const isCountingDown = !isTradeAvailable && Boolean(tradeAvailabilityDurationRemaining)

apps/web/src/features/Toucan/Auction/Banners/TokenLaunched/TokenLaunchedBannerInner.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ interface TokenLaunchedBannerInnerProps {
2121
accentColor: string
2222
isTradeAvailable: boolean
2323
tradeAvailabilityDurationRemaining: string | undefined
24+
// See TokenLaunchedBannerContent — set for redeemable virtual tokens to present the real token.
25+
fdvUsdOverride?: number | null
26+
tokenDetailsAddress?: string
2427
}
2528

2629
export function TokenLaunchedBannerInner({
@@ -32,6 +35,8 @@ export function TokenLaunchedBannerInner({
3235
accentColor,
3336
isTradeAvailable,
3437
tradeAvailabilityDurationRemaining,
38+
fdvUsdOverride,
39+
tokenDetailsAddress,
3540
}: TokenLaunchedBannerInnerProps) {
3641
const navigate = useNavigate()
3742
const auctionDetails = useAuctionStore((state) => state.auctionDetails)
@@ -41,11 +46,11 @@ export function TokenLaunchedBannerInner({
4146
return
4247
}
4348
const tokenDetailsURL = getTokenDetailsURL({
44-
address: auctionDetails.tokenAddress,
49+
address: tokenDetailsAddress ?? auctionDetails.tokenAddress,
4550
chain: toGraphQLChain(auctionDetails.chainId),
4651
})
4752
navigate(tokenDetailsURL)
48-
}, [auctionDetails, navigate])
53+
}, [auctionDetails, navigate, tokenDetailsAddress])
4954

5055
const canPress = Boolean(auctionDetails && isTradeAvailable)
5156

@@ -60,6 +65,8 @@ export function TokenLaunchedBannerInner({
6065
currentTickValue={priceData?.currentTickValue}
6166
isTradeAvailable={isTradeAvailable}
6267
tradeAvailabilityDurationRemaining={tradeAvailabilityDurationRemaining}
68+
fdvUsdOverride={fdvUsdOverride}
69+
tokenDetailsAddress={tokenDetailsAddress}
6370
/>
6471
</TouchableArea>
6572
</TokenLaunchedBannerWrapper>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { GraphQLApi } from '@universe/api'
2+
import { useMemo } from 'react'
3+
import { UniverseChainId } from 'uniswap/src/features/chains/types'
4+
import { toGraphQLChain } from 'uniswap/src/features/chains/utils'
5+
6+
interface UseRealTokenMarketInfoParams {
7+
tokenAddress?: string
8+
chainId?: UniverseChainId
9+
skip?: boolean
10+
}
11+
12+
interface RealTokenMarketInfo {
13+
fdvUsd: number | undefined
14+
name: string | undefined
15+
loading: boolean
16+
}
17+
18+
/**
19+
* Fetches a real (redeemable) token's indexed market data for the Token Launched Banner: its
20+
* name and fully-diluted valuation, from the same GraphQL source the token details page uses.
21+
*
22+
* Used when an auction's virtual token is redeemable, so the banner can present the real token's
23+
* own name + FDV (its price x its own total supply) instead of recomputing FDV from the virtual
24+
* token's clearing price and supply.
25+
*/
26+
export function useRealTokenMarketInfo({
27+
tokenAddress,
28+
chainId,
29+
skip = false,
30+
}: UseRealTokenMarketInfoParams): RealTokenMarketInfo {
31+
const chain = chainId ? toGraphQLChain(chainId) : undefined
32+
33+
const { data, loading } = GraphQLApi.useTokenWebQuery({
34+
variables: { chain: chain ?? GraphQLApi.Chain.Ethereum, address: tokenAddress },
35+
skip: skip || !chain || !tokenAddress,
36+
})
37+
38+
return useMemo(() => {
39+
const token = data?.token
40+
return {
41+
// Project market [0] is the aggregated USD market — same source as `useTokenMarketStats`.
42+
fdvUsd: token?.project?.markets?.[0]?.fullyDilutedValuation?.value ?? undefined,
43+
name: token?.name ?? token?.project?.name ?? undefined,
44+
loading,
45+
}
46+
}, [data?.token, loading])
47+
}

0 commit comments

Comments
 (0)