diff --git a/package.json b/package.json index 09be5eb84..6952fdac8 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "@cosmjs/tendermint-rpc": "^0.32.1", "@datadog/browser-logs": "^5.23.3", "@dydxprotocol/v4-client-js": "3.4.0", - "@dydxprotocol/v4-localization": "1.1.371", + "@dydxprotocol/v4-localization": "1.1.373", "@dydxprotocol/v4-proto": "^7.0.0-dev.0", "@emotion/is-prop-valid": "^1.3.0", "@hugocxl/react-to-image": "^0.0.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 49c7397eb..20b82bfdf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,8 +33,8 @@ dependencies: specifier: 3.4.0 version: 3.4.0 '@dydxprotocol/v4-localization': - specifier: 1.1.371 - version: 1.1.371 + specifier: 1.1.373 + version: 1.1.373 '@dydxprotocol/v4-proto': specifier: ^7.0.0-dev.0 version: 7.0.5 @@ -1732,8 +1732,8 @@ packages: - utf-8-validate dev: false - /@dydxprotocol/v4-localization@1.1.371: - resolution: {integrity: sha512-MoZWv3DSH9dQgy5jnUtdk4wUPBbe3p6kOWQz2/9gLc0y+sIwLr5LNqpSS6+dn43/Ni/mr8jcj0QwM9nrAvGhWQ==} + /@dydxprotocol/v4-localization@1.1.373: + resolution: {integrity: sha512-RIJGSm4DiqJS7oMyOUS5VeqVnu22fUzOZ0w5KIDEv6yIzLK2GXowfAxZjH3RBoy73mW9ox3Bjsz6stCRttExkA==} dev: false /@dydxprotocol/v4-proto@7.0.5: diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx index 2d4efbfa6..b7a25b19d 100644 --- a/src/components/Icon.tsx +++ b/src/components/Icon.tsx @@ -152,7 +152,6 @@ import { WithdrawIcon, XCircleIcon, } from '@/icons'; -import { ChaosLabsIcon } from '@/icons/chaos-labs'; import { LogoShortIcon } from '@/icons/logo-short'; import SignalIcon from '@/icons/signal.svg'; import UsdcIcon from '@/icons/usdc.svg'; @@ -177,7 +176,6 @@ export enum IconName { Caret = 'Caret', CautionCircle = 'CautionCircle', CautionCircleStroked = 'CautionCircleStroked', - ChaosLabs = 'ChaosLabs', Chat = 'Chat', ChefHat = 'ChefHat', Check = 'Check', @@ -336,7 +334,6 @@ const icons = { [IconName.Caret]: CaretIcon, [IconName.CautionCircle]: CautionCircleIcon, [IconName.CautionCircleStroked]: CautionCircleStrokeIcon, - [IconName.ChaosLabs]: ChaosLabsIcon, [IconName.Chat]: ChatIcon, [IconName.ChefHat]: ChefHatIcon, [IconName.Check]: CheckIcon, diff --git a/src/components/Link.tsx b/src/components/Link.tsx index e86d7fc8a..ae3de313a 100644 --- a/src/components/Link.tsx +++ b/src/components/Link.tsx @@ -1,4 +1,4 @@ -import { forwardRef } from 'react'; +import { forwardRef, HTMLAttributes } from 'react'; import styled, { css } from 'styled-components'; @@ -25,7 +25,10 @@ type StyleProps = { className?: string; }; -export const Link = forwardRef( +export const Link = forwardRef< + HTMLAnchorElement, + ElementProps & StyleProps & HTMLAttributes +>( ( { analyticsConfig, diff --git a/src/constants/statsig.ts b/src/constants/statsig.ts index 89ef31a72..600c4e912 100644 --- a/src/constants/statsig.ts +++ b/src/constants/statsig.ts @@ -17,6 +17,8 @@ export enum StatsigFlags { ffTurnkeyWeb = 'ff_turnkey_web', ffSwapEnabled = 'ff_swap_ui_web', ffSpot = 'ff_spot', + ffHideMarketsFilter = 'ff_hide_markets_filter', + ffOpenInterestFilter = 'ff_open_interest_filter', abPopupDeposit = 'ab_popup_deposit', ffSpotBonk = 'ff_spot_bonk', ffBonkPnlLeaderboard = 'ff_bonk_pnl_leaderboard', diff --git a/src/hooks/rewards/hooks.ts b/src/hooks/rewards/hooks.ts index 3c5a3fb51..0667dd1d3 100644 --- a/src/hooks/rewards/hooks.ts +++ b/src/hooks/rewards/hooks.ts @@ -1,133 +1,13 @@ import { BonsaiCore } from '@/bonsai/ontology'; import { useQuery } from '@tanstack/react-query'; -import { DydxAddress } from '@/constants/wallets'; - import { useAppSelector } from '@/state/appTypes'; import { wrapAndLogError } from '@/lib/asyncUtils'; -import { mapIfPresent } from '@/lib/do'; - -import { useQueryChaosLabsIncentives } from '../useQueryChaosLabsIncentives'; -import { - CURRENT_SURGE_REWARDS_DETAILS, - feesToEstimatedDollarRewards, - pointsToEstimatedDollarRewards, - pointsToEstimatedDydxRewards, -} from './util'; - -export type ChaosLabsPointsItem = { - rank: number; - account: DydxAddress; - accountLabel: string; - incentivePoints: number; - updatedAt: number; - estimatedDydxRewards: number | string; -}; - -const volumeQuery = `query VolumeLeaderboard($query: LeaderboardQuery!) {\n incentivesLeaderboard(query: $query) {\n rank\n account\n accountLabel\n markets\n incentivePoints\n updatedAt\n roi\n pnl\n __typename\n }\n}`; - -async function getChaosLabsPointsDistribution() { - const res = await fetch(`https://cloud.chaoslabs.co/query/ccar-perpetuals`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - protocol: 'dydx-v4', - 'apollographql-client-name': 'dydx-v4', - }, - body: JSON.stringify({ - operationName: 'VolumeLeaderboard', - query: volumeQuery, - variables: { - query: { - type: 'Volume', - skip: 0, - sort: 'takerFeesRank', - order: 'Ascending', - search: null, - }, - }, - }), - }); - const parsedRes = (await res.json()) as { - data: { incentivesLeaderboard: ChaosLabsPointsItem[] }; - }; - - return parsedRes.data.incentivesLeaderboard; -} - -export function useChaosLabsPointsDistribution() { - const { data: pointsInfo, isLoading: rewardsInfoLoading } = useTotalRewardsPoints(); - const dydxPrice = useAppSelector(BonsaiCore.rewardParams.data).tokenPrice; - - const { data: leaderboardItems, isLoading: leaderboardItemsLoading } = useQuery({ - queryKey: ['chaoslabs/points'], - queryFn: wrapAndLogError( - () => getChaosLabsPointsDistribution(), - 'LaunchIncentives/fetchDistribution', - true - ), - }); - - return { - isLoading: rewardsInfoLoading || leaderboardItemsLoading || !dydxPrice, - data: leaderboardItems?.map((item) => ({ - ...item, - estimatedDydxRewards: pointsToEstimatedDydxRewards( - item.incentivePoints, - pointsInfo?.totalPoints, - dydxPrice, - CURRENT_SURGE_REWARDS_DETAILS.rewardAmountUsd - ), - })), - }; -} -async function getTotalRewardsPoints() { - const res = await fetch('https://cloud.chaoslabs.co/query/api/dydx/total-points'); - const data = (await res.json()) as { totalPoints: number; seasonNumber: number }; - return data; -} +import { feesToEstimatedDollarRewards } from './util'; -export function useTotalRewardsPoints() { - return useQuery({ - queryKey: ['total-rewards-points'], - queryFn: () => getTotalRewardsPoints(), - }); -} - -export const useChaosLabsUsdRewards = ({ - dydxAddress, - season, - totalUsdRewards, -}: { - dydxAddress?: DydxAddress; - season?: number; - totalUsdRewards?: number; -}) => { - const { data: totalPoints, isLoading: totalPointsLoading } = useTotalRewardsPoints(); - const { data: points, isLoading: pointsLoading } = useQueryChaosLabsIncentives({ - dydxAddress, - season, - }); - - return { - data: mapIfPresent( - pointsToEstimatedDollarRewards( - points?.incentivePoints, - totalPoints?.totalPoints, - totalUsdRewards - ), - points?.totalFees, - (pointRewards, feesPaid) => { - return pointRewards + feesPaid; - } - ), - isLoading: totalPointsLoading || pointsLoading, - }; -}; - -export type ChaosLabsPnlItem = { +export type ClcPnlItem = { address: string; pnl: number; startOfThisWeekPnlSnapshot: { @@ -139,7 +19,7 @@ export type ChaosLabsPnlItem = { dollarReward: number; }; -async function getChaosLabsPnlDistribution() { +async function getClcPnlDistribution() { const res = await fetch( `https://pp-external-api-ffb2ad95ef03.herokuapp.com/api/dydx-weekly-clc?perPage=1000`, { @@ -147,22 +27,18 @@ async function getChaosLabsPnlDistribution() { } ); const parsedRes = (await res.json()) as { - data: ChaosLabsPnlItem[]; + data: ClcPnlItem[]; }; return parsedRes.data; } -export function useChaosLabsPnlDistribution() { +export function useClcPnlDistribution() { const dydxPrice = useAppSelector(BonsaiCore.rewardParams.data).tokenPrice; const { data: pnlItems, isLoading: pnlItemsLoading } = useQuery({ - queryKey: ['chaoslabs/pnls'], - queryFn: wrapAndLogError( - () => getChaosLabsPnlDistribution(), - 'LaunchIncentives/fetchPnls', - true - ), + queryKey: ['clc-pnls'], + queryFn: wrapAndLogError(() => getClcPnlDistribution(), 'LaunchIncentives/fetchPnls', true), }); return { @@ -171,13 +47,7 @@ export function useChaosLabsPnlDistribution() { }; } -export type ChaosLabsLeaderboardItem = { - rank: number; - account: string; - estimatedDydxRewards: string | number; -}; - -export type ChaosLabsCompetitionItem = { +export type IncentiveCompetitionItem = { rank: number; account: string; dollarReward: number; @@ -191,18 +61,18 @@ export type BonkPnlItem = { position: number; }; -export function useChaosLabsFeeLeaderboard({ address }: { address?: string }) { +export function useFeeLeaderboard({ address }: { address?: string }) { return useQuery({ - queryKey: ['chaoslabs/fee-leaderboard', address], + queryKey: ['dydx-fee-leaderboard', address], queryFn: wrapAndLogError( - () => getChaosLabsFeeLeaderboard({ address }), + () => getDydxFeeLeaderboard({ address }), 'LaunchIncentives/fetchFeeLeaderboard', true ), }); } -export type ChaosLabsFeeLeaderboardItemWithRewards = { +export type DydxFeeLeaderboardItemWithRewards = { address: string; total_fees: number; rank: number; @@ -210,16 +80,16 @@ export type ChaosLabsFeeLeaderboardItemWithRewards = { estimatedDydxRewards: number; }; -export type ChaosLabsFeeLeaderboardItem = { +export type DydxFeeLeaderboardItem = { address: string; total_fees: number; rank: number; }; -type ChaosLabsFeeLeaderboardResponse = { +type DydxFeeLeaderboardResponse = { success: boolean; - addressEntry?: ChaosLabsFeeLeaderboardItem; - data: ChaosLabsFeeLeaderboardItem[]; + addressEntry?: DydxFeeLeaderboardItem; + data: DydxFeeLeaderboardItem[]; pagination?: { total: number; totalPages: number; @@ -229,9 +99,9 @@ type ChaosLabsFeeLeaderboardResponse = { }; export const addRewardsToLeaderboardEntry = ( - entry: ChaosLabsFeeLeaderboardItem, + entry: DydxFeeLeaderboardItem, dydxPrice: number | undefined -): ChaosLabsFeeLeaderboardItemWithRewards => { +): DydxFeeLeaderboardItemWithRewards => { const dollarRewards = feesToEstimatedDollarRewards(entry.total_fees); const dydxRewards = dydxPrice ? dollarRewards / dydxPrice : 0; return { @@ -241,12 +111,12 @@ export const addRewardsToLeaderboardEntry = ( }; }; -async function getChaosLabsFeeLeaderboard({ address }: { address?: string }) { +async function getDydxFeeLeaderboard({ address }: { address?: string }) { const res = await fetch( `https://pp-external-api-ffb2ad95ef03.herokuapp.com/api/dydx-fee-leaderboard?perPage=1000${address ? `&address=${address}` : ''}` ); - const data = (await res.json()) as ChaosLabsFeeLeaderboardResponse; + const data = (await res.json()) as DydxFeeLeaderboardResponse; return { leaderboard: data.data, addressEntry: data.addressEntry, diff --git a/src/hooks/rewards/util.ts b/src/hooks/rewards/util.ts index b0c34997f..a7045a63d 100644 --- a/src/hooks/rewards/util.ts +++ b/src/hooks/rewards/util.ts @@ -20,18 +20,17 @@ export function pointsToEstimatedDollarRewards( export function feesToEstimatedDollarRewards(totalFees?: number): number { if (!totalFees) return 0; - return totalFees * 0.5; + return totalFees * CURRENT_SURGE_REWARDS_DETAILS.rebateFraction; } -// Move to Chaos Labs query once its available export const CURRENT_SURGE_REWARDS_DETAILS = { - season: 9, + season: 10, rewardAmount: '', rewardAmountUsd: 0, rebatePercent: '50%', rebatePercentNumeric: '50', rebateFraction: 0.5, - endTime: '2025-12-31T23:59:59.000Z', // end of month + endTime: '2026-01-31T23:59:59.000Z', // end of jan 2026 }; export const DEC_2025_COMPETITION_DETAILS = { diff --git a/src/hooks/surgeRewards.ts b/src/hooks/surgeRewards.ts deleted file mode 100644 index 512b75d7e..000000000 --- a/src/hooks/surgeRewards.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const CURRENT_REWARDS_SEASON_EXPIRATION = '2025-09-01T00:00:00.000Z'; -export const CURRENT_REWARDS_SEASON = 5; -export const CURRENT_REWARDS_SEASON_AMOUNT = 3; diff --git a/src/hooks/useMarketsData.ts b/src/hooks/useMarketsData.ts index db1b42f51..634540102 100644 --- a/src/hooks/useMarketsData.ts +++ b/src/hooks/useMarketsData.ts @@ -11,6 +11,9 @@ import { MarketFilters, type MarketData, } from '@/constants/markets'; +import { StatsigFlags } from '@/constants/statsig'; + +import { useStatsigGateValue } from '@/hooks/useStatsig'; import { useAppSelector } from '@/state/appTypes'; import { getFavoritedMarkets, getShouldHideLaunchableMarkets } from '@/state/appUiConfigsSelectors'; @@ -75,7 +78,7 @@ const sortByMarketCap = (a: AssetData, b: AssetData) => { return (b.marketCap ?? 0) - (a.marketCap ?? 0); }; -const ASSETS_TO_REMOVE = new Set(['USDC', 'USDT', ...HIDDEN_MARKETS]); +const ASSETS_TO_REMOVE = new Set(['USDC', 'USDT', 'USD1', 'USDE']); export const useMarketsData = ({ filter = MarketFilters.ALL, searchFilter, @@ -101,6 +104,9 @@ export const useMarketsData = ({ const favoritedMarkets = useAppSelector(getFavoritedMarkets, shallowEqual); const hasMarketIds = Object.keys(perpetualMarkets).length > 0; + const shouldFilterHiddenMarkets = useStatsigGateValue(StatsigFlags.ffHideMarketsFilter); + const shouldFilterOpenInterest = useStatsigGateValue(StatsigFlags.ffOpenInterestFilter); + // AssetIds from existing PerpetualMarkets const marketsAssetIdSet = useMemo( () => @@ -119,8 +125,10 @@ export const useMarketsData = ({ .filter((m) => m.status !== 'FINAL_SETTLEMENT') // temporarily filter out markets with empty/0 oracle price and $0 open interest .filter((m) => MustBigNumber(m.oraclePrice).gt(0)) - .filter((m) => MustBigNumber(m.openInterestUSDC).gt(0)) - .filter((m) => !HIDDEN_MARKETS.has(m.assetId)) + // filter out markets with $0 open interest (when gate is enabled) + .filter((m) => !shouldFilterOpenInterest || MustBigNumber(m.openInterestUSDC).gt(0)) + // filter out hidden markets (when gate is enabled) + .filter((m) => !shouldFilterHiddenMarkets || !HIDDEN_MARKETS.has(m.assetId)) .map(getMarketDataFromPerpetualMarketSummary); const unlaunchedMarketsData = @@ -128,6 +136,8 @@ export const useMarketsData = ({ ? Object.values(assets) .filter(isTruthy) .filter((a) => !ASSETS_TO_REMOVE.has(a.assetId)) + // filter out hidden markets (when gate is enabled) + .filter((a) => !shouldFilterHiddenMarkets || !HIDDEN_MARKETS.has(a.assetId)) .sort(sortByMarketCap) .map((asset) => { // Remove assets that are already in the list of markets from Indexer a long with assets that have no price or a negative price @@ -143,11 +153,13 @@ export const useMarketsData = ({ return [...listOfMarkets, ...unlaunchedMarketsData]; }, [ perpetualMarkets, - marketsAssetIdSet, + forceShowUnlaunchedMarkets, + shouldHideLaunchableMarkets, assets, + shouldFilterOpenInterest, + shouldFilterHiddenMarkets, + marketsAssetIdSet, favoritedMarkets, - shouldHideLaunchableMarkets, - forceShowUnlaunchedMarkets, ]); const filteredMarkets = useMemo(() => { diff --git a/src/hooks/useNotificationTypes.tsx b/src/hooks/useNotificationTypes.tsx index 9f57c2a40..0ffbcdec6 100644 --- a/src/hooks/useNotificationTypes.tsx +++ b/src/hooks/useNotificationTypes.tsx @@ -2,8 +2,7 @@ import { useEffect, useMemo, useRef } from 'react'; import { BonsaiCore } from '@/bonsai/ontology'; import { OrderStatus, SubaccountFillType } from '@/bonsai/types/summaryTypes'; -import { useQuery } from '@tanstack/react-query'; -import { groupBy, isNumber, max, pick } from 'lodash'; +import { groupBy, max, pick } from 'lodash'; import { shallowEqual } from 'react-redux'; import tw from 'twin.macro'; @@ -26,12 +25,6 @@ import { timeUnits } from '@/constants/time'; import { PlaceOrderStatuses } from '@/constants/trade'; import { IndexerOrderSide, IndexerOrderType } from '@/types/indexer/indexerApiGen'; -import { - CURRENT_REWARDS_SEASON, - CURRENT_REWARDS_SEASON_AMOUNT, - CURRENT_REWARDS_SEASON_EXPIRATION, -} from '@/hooks/surgeRewards'; - import { Icon, IconName } from '@/components/Icon'; import { Link } from '@/components/Link'; import { formatNumberOutput, Output, OutputType } from '@/components/Output'; @@ -79,7 +72,6 @@ import { } from '@/lib/enumToStringKeyHelpers'; import { BIG_NUMBERS, MaybeBigNumber, MustNumber } from '@/lib/numbers'; import { getAverageFillPrice } from '@/lib/orders'; -import { sleep } from '@/lib/timeUtils'; import { isPresent, orEmptyRecord } from '@/lib/typeUtils'; import { DEC_2025_COMPETITION_DETAILS } from './rewards/util'; @@ -576,163 +568,9 @@ export const notificationTypes: NotificationTypeConfig[] = [ useTrigger: ({ trigger }) => { const stringGetter = useStringGetter(); const dydxAddress = useAppSelector(getUserWalletAddress); - const currentSeason = CURRENT_REWARDS_SEASON; const { decimal: decimalSeparator, group: groupSeparator } = useLocaleSeparators(); const selectedLocale = useAppSelector(getSelectedLocale); - const { data: rewards } = useQuery({ - queryKey: ['dydx-surge-rewards', currentSeason, dydxAddress], - enabled: - dydxAddress != null && - new Date().getTime() < new Date(CURRENT_REWARDS_SEASON_EXPIRATION).getTime(), - retry: false, - queryFn: async () => { - try { - // don't take up bandwidth during sensitive loading time - await sleep(1500); - const data = await fetch( - `https://cloud.chaoslabs.co/query/api/dydx/reward-distribution?season=${currentSeason - 1}` - ); - const result = await data.json(); - const maybeNumber = result.find((f: any) => f.address === dydxAddress).rewards; - if (isNumber(maybeNumber)) { - return maybeNumber; - } - return null; - } catch (e) { - return null; - } - }, - }); - - useEffect(() => { - const now = new Date().getTime(); - const seasonEnd = new Date(CURRENT_REWARDS_SEASON_EXPIRATION).getTime(); - if (now < seasonEnd && rewards != null && rewards > 5) { - trigger({ - id: `rewards-program-surge-s${currentSeason - 1}-payout`, - displayData: { - icon: , - title: stringGetter({ - key: STRING_KEYS.SURGE_PAYOUT_TITLE, - params: { SEASON_NUMBER: currentSeason - 1, DYDX_REWARDS: rewards }, - }), - body: stringGetter({ - key: STRING_KEYS.SURGE_PAYOUT_BODY, - params: { - SEASON_NUMBER: currentSeason - 1, - }, - }), - toastSensitivity: 'foreground', - groupKey: NotificationType.RewardsProgramUpdates, - actionAltText: stringGetter({ key: STRING_KEYS.LEARN_MORE }), - renderActionSlot: () => ( - - {stringGetter({ key: STRING_KEYS.LEARN_MORE })} → - - ), - }, - updateKey: [`rewards-program-surge-s${currentSeason - 1}-payout`], - }); - } - }, [currentSeason, rewards, stringGetter, trigger]); - - useEffect(() => { - const now = new Date().getTime(); - const seasonEnd = new Date(CURRENT_REWARDS_SEASON_EXPIRATION).getTime(); - const endingSoon = seasonEnd - timeUnits.day * 3; - - if (now <= endingSoon) { - trigger({ - id: `rewards-program-surge-s${currentSeason}-start`, - displayData: { - icon: , - title: stringGetter({ - key: STRING_KEYS.SURGE_BASIC_SEASON_TITLE, - params: { - SEASON_NUMBER: currentSeason, - AMOUNT_MILLIONS: CURRENT_REWARDS_SEASON_AMOUNT, - }, - }), - body: stringGetter({ - key: STRING_KEYS.SURGE_BASIC_SEASON_BODY, - params: { - SEASON_NUMBER: currentSeason, - AMOUNT_MILLIONS: CURRENT_REWARDS_SEASON_AMOUNT, - }, - }), - toastSensitivity: 'foreground', - groupKey: NotificationType.RewardsProgramUpdates, - actionAltText: stringGetter({ key: STRING_KEYS.LEARN_MORE }), - renderActionSlot: () => ( - - {stringGetter({ key: STRING_KEYS.LEARN_MORE })} → - - ), - }, - updateKey: [`rewards-program-surge-s${currentSeason}-start`], - }); - } else if (now < seasonEnd) { - let daysLeft = Math.floor((seasonEnd - now) / timeUnits.day); - // oops, we don't want to show 1 days left or 0 days left - if (daysLeft < 2) { - daysLeft = 2; - } - trigger({ - id: `rewards-program-surge-s${currentSeason}-ending`, - displayData: { - icon: , - title: stringGetter({ - key: STRING_KEYS.SURGE_SEASON_ENDING_TITLE, - params: { SEASON_NUMBER: currentSeason, DAYS_LEFT: daysLeft }, - }), - body: stringGetter({ - key: STRING_KEYS.SURGE_SEASON_ENDING_BODY, - params: { - SEASON_NUMBER: currentSeason, - DAYS_LEFT: daysLeft, - }, - }), - toastSensitivity: 'foreground', - groupKey: NotificationType.RewardsProgramUpdates, - actionAltText: stringGetter({ key: STRING_KEYS.LEARN_MORE }), - renderActionSlot: () => ( - - {stringGetter({ key: STRING_KEYS.LEARN_MORE })} → - - ), - }, - updateKey: [`rewards-program-surge-s${currentSeason}-ending`], - }); - } - }, [currentSeason, stringGetter, trigger]); - - const PUMP_COMPETITION_EXPIRATION = '2025-07-29T00:00:00.000Z'; - useEffect(() => { - if (new Date().getTime() < new Date(PUMP_COMPETITION_EXPIRATION).getTime()) - trigger({ - id: `pump-trading-competition-base`, - displayData: { - icon: , - title: stringGetter({ - key: STRING_KEYS.PUMP_COMPETITION_TITLE, - }), - body: stringGetter({ - key: STRING_KEYS.PUMP_COMPETITION_BODY, - }), - toastSensitivity: 'foreground', - groupKey: NotificationType.RewardsProgramUpdates, - actionAltText: stringGetter({ key: STRING_KEYS.LEARN_MORE }), - renderActionSlot: () => ( - - {stringGetter({ key: STRING_KEYS.LEARN_MORE })} → - - ), - }, - updateKey: [`pump-trading-competition-base`], - }); - }, [stringGetter, trigger]); - useEffect(() => { if ( new Date().getTime() < new Date(DEC_2025_COMPETITION_DETAILS.claimEndtime).getTime() && diff --git a/src/hooks/useQueryChaosLabsIncentives.ts b/src/hooks/useQueryChaosLabsIncentives.ts deleted file mode 100644 index 766835cf5..000000000 --- a/src/hooks/useQueryChaosLabsIncentives.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { DateTime } from 'luxon'; - -import type { DydxAddress } from '@/constants/wallets'; - -import { wrapAndLogError } from '@/lib/asyncUtils'; -import { calc } from '@/lib/do'; - -type ChaosLabsIncentivesResponse = { - incentivePoints: number; - marketMakingIncentivePoints: number; - totalFees: number; -}; - -export const useQueryChaosLabsIncentives = ({ - dydxAddress, - season, -}: { - dydxAddress?: DydxAddress; - season?: number; -}) => { - return useQuery({ - enabled: !!dydxAddress, - queryKey: ['launch_incentives_rewards', dydxAddress, season], - queryFn: wrapAndLogError( - async (): Promise => { - if (!dydxAddress) return undefined; - - // If season is defined, fetch for a specific season - if (season !== undefined) { - const resp = await fetch( - `https://cloud.chaoslabs.co/query/api/dydx/points/${dydxAddress}?n=${season}` - ); - return resp.json(); - } - - const currentSeason: number | undefined = await calc(async () => { - const resp = await fetch(`https://cloud.chaoslabs.co/query/api/dydx/season`); - return (await resp.json()).currentSeason; - }); - - if (currentSeason == null) { - return undefined; - } - - const [thisSeasonResponse, thisSeasonFees] = await Promise.all([ - calc(async () => { - return ( - await fetch( - `https://cloud.chaoslabs.co/query/api/dydx/points/${dydxAddress}?n=${currentSeason}` - ) - ).json(); - }), - calc(async () => { - return ( - await fetch( - `https://cloud.chaoslabs.co/query/api/dydx/fees/${dydxAddress}?month=${DateTime.utc().toFormat('yyyy-MM')}` - ) - ).json(); - }), - ]); - - return { - incentivePoints: thisSeasonResponse.incentivePoints ?? 0, - marketMakingIncentivePoints: thisSeasonResponse.marketMakingIncentivePoints ?? 0, - totalFees: thisSeasonFees.data?.[0]?.total_fees ?? 0, - }; - }, - 'LaunchIncentives/fetchPoints', - true - ), - }); -}; diff --git a/src/icons/chaos-labs.tsx b/src/icons/chaos-labs.tsx deleted file mode 100644 index 3ecda6463..000000000 --- a/src/icons/chaos-labs.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { useAppSelector } from '@/state/appTypes'; -import { AppTheme } from '@/state/appUiConfigs'; -import { getAppTheme } from '@/state/appUiConfigsSelectors'; - -export const ChaosLabsIcon: React.FC = () => { - const appTheme = useAppSelector(getAppTheme); - - const fills = appTheme === AppTheme.Light ? ['#1482E5', '#000000'] : ['#1482E5', '#E5E9EB']; - - return ( - - - - - - - - - - - - - - ); -}; diff --git a/src/icons/index.ts b/src/icons/index.ts index 5a40d27d2..d768a1a7b 100644 --- a/src/icons/index.ts +++ b/src/icons/index.ts @@ -171,11 +171,6 @@ export { default as WalletConnectIcon } from './wallets/walletconnect.svg'; export { default as WebsiteIcon } from './website.svg'; export { default as WhitepaperIcon } from './whitepaper.svg'; -// Logos -// Commented out because of https://github.com/dydxprotocol/v4-web/pull/737 -// Left as comment for context in case people wonder why they're not imported here -// export { default as ChaosLabsIcon } from './chaos-labs'; -// export { default as LogoShortIcon } from './logo-short'; export { default as EtherscanIcon } from './logos/etherscan.svg'; export { default as PoweredByTurnkeyIcon } from './logos/powered-by-turnkey.svg'; diff --git a/src/pages/markets/MarketsBanners.tsx b/src/pages/markets/MarketsBanners.tsx index 162ffe4e7..0fd56347a 100644 --- a/src/pages/markets/MarketsBanners.tsx +++ b/src/pages/markets/MarketsBanners.tsx @@ -181,7 +181,7 @@ export const MarketsBanners = ({ {stringGetter({ key: STRING_KEYS.NO_FEE_NOVEMBER_BANNER_TITLE_ACCENT })} {' '} - {stringGetter({ key: STRING_KEYS.NO_FEE_DECEMBER_BANNER_TITLE })} + {stringGetter({ key: STRING_KEYS.NO_FEE_JANUARY_BANNER_TITLE })} {stringGetter({ key: STRING_KEYS.NO_FEE_NOVEMBER_BANNER_CTA })} → diff --git a/src/pages/token/CompetitionIncentivesPanel.tsx b/src/pages/token/CompetitionIncentivesPanel.tsx index 735f1b433..312f75af0 100644 --- a/src/pages/token/CompetitionIncentivesPanel.tsx +++ b/src/pages/token/CompetitionIncentivesPanel.tsx @@ -6,7 +6,7 @@ import tw from 'twin.macro'; import { STRING_KEYS } from '@/constants/localization'; -import { useChaosLabsPnlDistribution } from '@/hooks/rewards/hooks'; +import { useClcPnlDistribution } from '@/hooks/rewards/hooks'; import { DEC_2025_COMPETITION_DETAILS } from '@/hooks/rewards/util'; import { useAccounts } from '@/hooks/useAccounts'; import { useNow } from '@/hooks/useNow'; @@ -108,7 +108,7 @@ const September2025RewardsPanel = () => { const Sept2025RewardsPanel = () => { const stringGetter = useStringGetter(); const { dydxAddress } = useAccounts(); - const { data: topPnls, isLoading } = useChaosLabsPnlDistribution(); + const { data: topPnls, isLoading } = useClcPnlDistribution(); const userReward = topPnls?.find((entry) => entry.address === dydxAddress)?.dollarReward ?? 0; diff --git a/src/pages/token/CompetitionLeaderboardPanel.tsx b/src/pages/token/CompetitionLeaderboardPanel.tsx index 4abc520a0..154e12869 100644 --- a/src/pages/token/CompetitionLeaderboardPanel.tsx +++ b/src/pages/token/CompetitionLeaderboardPanel.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import { STRING_KEYS, StringGetterFunction } from '@/constants/localization'; -import { ChaosLabsCompetitionItem, useChaosLabsPnlDistribution } from '@/hooks/rewards/hooks'; +import { IncentiveCompetitionItem, useClcPnlDistribution } from '@/hooks/rewards/hooks'; import { CURRENT_SURGE_REWARDS_DETAILS } from '@/hooks/rewards/util'; import { useAccounts } from '@/hooks/useAccounts'; import { useStringGetter } from '@/hooks/useStringGetter'; @@ -30,10 +30,10 @@ export enum RewardsLeaderboardTableColumns { export const CompetitionLeaderboardPanel = () => { const stringGetter = useStringGetter(); - const { data: topPnls, isLoading } = useChaosLabsPnlDistribution(); + const { data: topPnls, isLoading } = useClcPnlDistribution(); const { dydxAddress } = useAccounts(); - const getRowKey = useCallback((row: ChaosLabsCompetitionItem) => row.rank, []); + const getRowKey = useCallback((row: IncentiveCompetitionItem) => row.rank, []); const columns = Object.values(RewardsLeaderboardTableColumns).map( (key: RewardsLeaderboardTableColumns) => @@ -54,7 +54,7 @@ export const CompetitionLeaderboardPanel = () => { pnl: +entry.pnl, }, ]; - }, [] as ChaosLabsCompetitionItem[]); + }, [] as IncentiveCompetitionItem[]); const onDownload = () => { if (data.length === 0) return; @@ -194,7 +194,7 @@ const getRewardsLeaderboardTableColumnDef = ({ key: RewardsLeaderboardTableColumns; stringGetter: StringGetterFunction; dydxAddress?: string; -}): ColumnDef => ({ +}): ColumnDef => ({ ...( { [RewardsLeaderboardTableColumns.Rank]: { @@ -273,6 +273,6 @@ const getRewardsLeaderboardTableColumnDef = ({ ), }, - } satisfies Record> + } satisfies Record> )[key], }); diff --git a/src/pages/token/LaunchIncentivesPanel.tsx b/src/pages/token/LaunchIncentivesPanel.tsx index e7e8849a6..8cae898b5 100644 --- a/src/pages/token/LaunchIncentivesPanel.tsx +++ b/src/pages/token/LaunchIncentivesPanel.tsx @@ -5,25 +5,17 @@ import { Duration } from 'luxon'; import styled from 'styled-components'; import tw from 'twin.macro'; -import { ButtonAction } from '@/constants/buttons'; -import { DialogTypes } from '@/constants/dialogs'; import { STRING_KEYS } from '@/constants/localization'; -import { TOKEN_DECIMALS } from '@/constants/numbers'; -import { addRewardsToLeaderboardEntry, useChaosLabsFeeLeaderboard } from '@/hooks/rewards/hooks'; +import { addRewardsToLeaderboardEntry, useFeeLeaderboard } from '@/hooks/rewards/hooks'; import { CURRENT_SURGE_REWARDS_DETAILS } from '@/hooks/rewards/util'; import { useAccounts } from '@/hooks/useAccounts'; -import { useBreakpoints } from '@/hooks/useBreakpoints'; import { useNow } from '@/hooks/useNow'; -import { useQueryChaosLabsIncentives } from '@/hooks/useQueryChaosLabsIncentives'; // import { useStatsigGateValue } from '@/hooks/useStatsig'; import { useStringGetter } from '@/hooks/useStringGetter'; -import { ChaosLabsIcon } from '@/icons/chaos-labs'; -import breakpoints from '@/styles/breakpoints'; import { layoutMixins } from '@/styles/layoutMixins'; -import { Button } from '@/components/Button'; import { Icon, IconName } from '@/components/Icon'; import { Link } from '@/components/Link'; import { Output, OutputType } from '@/components/Output'; @@ -33,44 +25,18 @@ import { WithTooltip } from '@/components/WithTooltip'; import { useAppDispatch, useAppSelector } from '@/state/appTypes'; import { markLaunchIncentivesSeen } from '@/state/appUiConfigs'; -import { openDialog } from '@/state/dialogs'; -export const LaunchIncentivesPanel = ({ className }: { className?: string }) => { - const { isNotTablet } = useBreakpoints(); +export const LaunchIncentivesPanel = () => { const dispatch = useAppDispatch(); useEffect(() => { dispatch(markLaunchIncentivesSeen()); }, [dispatch]); - // NOTE: may need to remove this ff check - // const isSept2025RewardsBase = useStatsigGateValue(StatsigFlags.ffSeptember2025Rewards); - // const isSept2025Rewards = isSept2025RewardsBase; - // if (isSept2025Rewards) { - // return ; - // } - - return isNotTablet ? ( - // <$Panel - // className={className} - // slotHeader={} - // slotRight={} - // > - // - // - - ) : ( - <$Panel className={className}> - <$Column> - - - - - - ); + return ; }; -const September2025RewardsPanel = () => { +const IncentivesRewardsPanel = () => { const stringGetter = useStringGetter(); return ( @@ -124,18 +90,18 @@ const September2025RewardsPanel = () => { - + ); }; -const Sept2025RewardsPanel = () => { +const EstimatedMonthlyRewards = () => { const stringGetter = useStringGetter(); const { dydxAddress } = useAccounts(); const dydxPrice = useAppSelector(BonsaiCore.rewardParams.data).tokenPrice; - const { data, isLoading } = useChaosLabsFeeLeaderboard({ + const { data, isLoading } = useFeeLeaderboard({ address: dydxAddress, }); const addressEntry = useMemo( @@ -178,135 +144,20 @@ const Sept2025RewardsPanel = () => {
- {stringGetter({ key: STRING_KEYS.POWERED_BY_ALL_CAPS })} -
- - ); -}; - -const IncentiveProgramDescription = () => { - const stringGetter = useStringGetter(); - - const howItWorks = ( -
    -
  • {stringGetter({ key: STRING_KEYS.SURGE_HOW_IT_WORKS_1 })}
  • -
  • {stringGetter({ key: STRING_KEYS.SURGE_HOW_IT_WORKS_2 })}
  • -
  • {stringGetter({ key: STRING_KEYS.SURGE_HOW_IT_WORKS_3 })}
  • -
- ); - - const howToEarnMore = ( -
    -
  • {stringGetter({ key: STRING_KEYS.SURGE_HOW_TO_EARN_1 })}
  • -
  • {stringGetter({ key: STRING_KEYS.SURGE_HOW_TO_EARN_2 })}
  • -
- ); - - return ( -
-
- {stringGetter({ key: STRING_KEYS.SURGE_HOW_IT_WORKS })} - {howItWorks} -
-
- {stringGetter({ key: STRING_KEYS.SURGE_HOW_TO_EARN })} - {howToEarnMore} + {stringGetter({ key: STRING_KEYS.POWERED_BY_ALL_CAPS })}{' '} + + CLC +
); }; -const LaunchIncentivesTitle = () => { - const stringGetter = useStringGetter(); - - return ( - <$Title> - {stringGetter({ - key: STRING_KEYS.SURGE_HEADLINE, - })} - {stringGetter({ key: STRING_KEYS.ACTIVE })} - }> - - - - ); -}; - -const EstimatedRewards = () => { - const stringGetter = useStringGetter(); - const { dydxAddress } = useAccounts(); - - const { data, isLoading } = useQueryChaosLabsIncentives({ dydxAddress }); - const { incentivePoints } = data ?? {}; - - return ( - <$EstimatedRewardsCard> - <$EstimatedRewardsCardContent> -
- {stringGetter({ key: STRING_KEYS.ESTIMATED_POINTS })} - - {stringGetter({ key: STRING_KEYS.TOTAL_POINTS })} - -
- - <$Points> - - {incentivePoints !== undefined && stringGetter({ key: STRING_KEYS.POINTS })} - - - - reward-stars - - ); -}; - -const LaunchIncentivesContent = () => { - const stringGetter = useStringGetter(); - const dispatch = useAppDispatch(); - - return ( - <$Column> -
- {stringGetter({ - key: STRING_KEYS.SURGE_BODY, - })}{' '} -
- - - {stringGetter({ key: STRING_KEYS.POWERED_BY_ALL_CAPS })} - - <$ButtonRow> - <$Button - action={ButtonAction.Secondary} - onClick={() => { - dispatch( - openDialog( - DialogTypes.ExternalLink({ - link: 'https://community.chaoslabs.xyz/dydx-v4/risk/leaderboard', - }) - ) - ); - }} - slotRight={} - slotLeft={} - tw="grow-[2]" - > - {stringGetter({ key: STRING_KEYS.LEADERBOARD })} - - - - ); -}; - const MinutesCountdown = ({ endTime }: { endTime: string }) => { const targetMs = Date.parse(endTime); const now = useNow(); @@ -332,74 +183,6 @@ const MinutesCountdown = ({ endTime }: { endTime: string }) => { const $Panel = tw(Panel)`bg-color-layer-3 w-full`; -const $Title = styled.h3` - ${layoutMixins.inlineRow} - font: var(--font-medium-book); - color: var(--color-text-2); - - @media ${breakpoints.notTablet} { - padding: var(--panel-paddingY) var(--panel-paddingX) 0; - } -`; - -const $ButtonRow = styled.div` - ${layoutMixins.inlineRow} - gap: 0.75rem; - margin-top: 0.5rem; - - a:last-child { - --button-width: 100%; - } -`; - -const $Button = styled(Button)` - --button-padding: 0 1rem; - - --button-textColor: var(--color-text-2); - --button-backgroundColor: var(--color-layer-6); - --button-border: solid var(--border-width) var(--color-layer-7); -`; - -const $Column = tw.div`flexColumn gap-0.5`; - -const $EstimatedRewardsCard = styled.div` - ${layoutMixins.spacedRow} - padding: 1rem 1.25rem; - min-width: 19rem; - height: calc(100% - calc(1.5rem * 2)); - max-height: 10rem; - margin: 1.5rem; - - background-color: var(--color-layer-5); - background-image: url('/dots-background.svg'); - background-size: cover; - - border-radius: 0.75rem; - border: solid var(--border-width) var(--color-layer-6); - color: var(--color-text-1); - - @media ${breakpoints.tablet} { - margin: 0 0 0.5rem; - } -`; - -const $EstimatedRewardsCardContent = styled.div` - ${layoutMixins.flexColumn} - gap: 1rem; - height: 100%; - justify-content: space-between; - - div { - ${layoutMixins.flexColumn} - gap: 0.15rem; - font: var(--font-medium-book); - - &:first-child { - color: var(--color-text-2); - } - } -`; - const $Points = styled.span` ${layoutMixins.inlineRow} gap: 0.25rem; diff --git a/src/pages/token/RewardsLeaderboardPanel.tsx b/src/pages/token/RewardsLeaderboardPanel.tsx index 52a1d062d..8695230f1 100644 --- a/src/pages/token/RewardsLeaderboardPanel.tsx +++ b/src/pages/token/RewardsLeaderboardPanel.tsx @@ -7,9 +7,9 @@ import { STRING_KEYS, StringGetterFunction } from '@/constants/localization'; import { addRewardsToLeaderboardEntry, - ChaosLabsFeeLeaderboardItem, - ChaosLabsFeeLeaderboardItemWithRewards, - useChaosLabsFeeLeaderboard, + DydxFeeLeaderboardItem, + DydxFeeLeaderboardItemWithRewards, + useFeeLeaderboard, } from '@/hooks/rewards/hooks'; import { CURRENT_SURGE_REWARDS_DETAILS } from '@/hooks/rewards/util'; import { useAccounts } from '@/hooks/useAccounts'; @@ -39,7 +39,7 @@ export const RewardsLeaderboardPanel = () => { const stringGetter = useStringGetter(); const { dydxAddress } = useAccounts(); const dydxPrice = useAppSelector(BonsaiCore.rewardParams.data).tokenPrice; - const { data: feeLeaderboardWithoutRewards, isLoading } = useChaosLabsFeeLeaderboard({ + const { data: feeLeaderboardWithoutRewards, isLoading } = useFeeLeaderboard({ address: dydxAddress, }); const feeLeaderboard = useMemo( @@ -50,7 +50,7 @@ export const RewardsLeaderboardPanel = () => { [feeLeaderboardWithoutRewards?.leaderboard, dydxPrice] ); - const getRowKey = useCallback((row: ChaosLabsFeeLeaderboardItem) => row.rank, []); + const getRowKey = useCallback((row: DydxFeeLeaderboardItem) => row.rank, []); const columns = Object.values(RewardsLeaderboardTableColumns).map( (key: RewardsLeaderboardTableColumns) => @@ -199,7 +199,7 @@ const getRewardsLeaderboardTableColumnDef = ({ key: RewardsLeaderboardTableColumns; stringGetter: StringGetterFunction; dydxAddress?: string; -}): ColumnDef => ({ +}): ColumnDef => ({ ...( { [RewardsLeaderboardTableColumns.Rank]: { @@ -269,9 +269,6 @@ const getRewardsLeaderboardTableColumnDef = ({ /> ), }, - } satisfies Record< - RewardsLeaderboardTableColumns, - ColumnDef - > + } satisfies Record> )[key], }); diff --git a/src/pages/token/Swap.tsx b/src/pages/token/Swap.tsx index 7207263a2..cec2d145f 100644 --- a/src/pages/token/Swap.tsx +++ b/src/pages/token/Swap.tsx @@ -46,7 +46,7 @@ import { addSwap } from '@/state/swaps'; import { track } from '@/lib/analytics/analytics'; import { escapeRegExp, numericValueRegex } from '@/lib/inputUtils'; -import { BIG_NUMBERS, MustBigNumber } from '@/lib/numbers'; +import { BIG_NUMBERS } from '@/lib/numbers'; type SwapMode = 'exact-in' | 'exact-out'; function otherToken(currToken: 'usdc' | 'dydx') { @@ -81,7 +81,7 @@ export const Swap = () => { ); const dydx = { rawBalanceBigInt: parseUnits(`${usableDydxBalance}`, DYDX_DECIMALS), - formatted: MustBigNumber(usableDydxBalance).toFormat(2, BigNumber.ROUND_DOWN), + rawBalance: usableDydxBalance, }; const usableUsdcBalance = Math.max( (parentSubaccountUsdcBalance ?? 0) - AMOUNT_RESERVED_FOR_GAS_USDC, @@ -89,7 +89,7 @@ export const Swap = () => { ); const usdc = { rawBalanceBigInt: parseUnits(`${usableUsdcBalance}`, USDC_DECIMALS), - formatted: MustBigNumber(usableUsdcBalance).toFormat(2, BigNumber.ROUND_DOWN), + rawBalance: usableUsdcBalance, }; return { @@ -114,9 +114,9 @@ export const Swap = () => { const setMaxAmount = (m: SwapMode) => { if (m === 'exact-in') { - setAmount(tokenBalances.inputBalance.formatted); + setAmount(`${tokenBalances.inputBalance.rawBalance}`); } else { - setAmount(tokenBalances.outputBalance.formatted); + setAmount(`${tokenBalances.outputBalance.rawBalance}`); } setMode(m); }; @@ -214,15 +214,11 @@ export const Swap = () => { onClick={() => setMaxAmount('exact-in')} > - {tokenBalances.inputBalance.formatted ? ( - - ) : ( - `- ${getTokenLabel(inputToken)}` - )} + @@ -266,15 +262,11 @@ export const Swap = () => { tw="flex h-fit items-center gap-0.375 p-0 font-small-medium hover:[--button-textColor:var(--color-text-1)]" > - {tokenBalances.outputBalance.formatted ? ( - - ) : ( - `- ${getTokenLabel(otherToken(inputToken))}` - )} +
diff --git a/src/pages/vaults/VaultInfoSections.tsx b/src/pages/vaults/VaultInfoSections.tsx index 4dbf4ac9e..9ea9fe64d 100644 --- a/src/pages/vaults/VaultInfoSections.tsx +++ b/src/pages/vaults/VaultInfoSections.tsx @@ -10,7 +10,6 @@ import { AppRoute } from '@/constants/routes'; import { tooltipStrings } from '@/constants/tooltips'; import { useBreakpoints } from '@/hooks/useBreakpoints'; -import { useEnvConfig } from '@/hooks/useEnvConfig'; import { useStringGetter } from '@/hooks/useStringGetter'; import { useURLConfigs } from '@/hooks/useURLConfigs'; import { @@ -102,40 +101,21 @@ const $DetailCard = styled.div` `; export const VaultDescription = ({ className }: { className?: string }) => { const stringGetter = useStringGetter(); - const { vaultOperatorLearnMore, vaultLearnMore } = useURLConfigs(); - const operatorName = useEnvConfig('megavaultOperatorName'); + return (

{stringGetter({ - key: STRING_KEYS.VAULT_DESCRIPTION, - })}{' '} - {vaultLearnMore && ( - - {stringGetter({ key: STRING_KEYS.LEARN_MORE_ABOUT_MEGAVAULT })} - - )} + key: STRING_KEYS.MEGAVAULT_DISCLOSURE_TEXT, + params: { + VOTED_LINK: ( + + {stringGetter({ key: STRING_KEYS.VOTED })} + + ), + }, + })}

- {operatorName.length > 0 && ( -

- {stringGetter({ - key: STRING_KEYS.VAULT_OPERATOR_DESCRIPTION, - params: { - OPERATOR_NAME: operatorName, - }, - })}{' '} - {vaultOperatorLearnMore && ( - - {stringGetter({ - key: STRING_KEYS.LEARN_MORE_ABOUT_OPERATOR, - params: { - OPERATOR_NAME: operatorName, - }, - })} - - )} -

- )}
); }; diff --git a/src/views/dialogs/TransferDialogs/WithdrawDialog2/AmountInput.tsx b/src/views/dialogs/TransferDialogs/WithdrawDialog2/AmountInput.tsx index ceea38b00..8176e519d 100644 --- a/src/views/dialogs/TransferDialogs/WithdrawDialog2/AmountInput.tsx +++ b/src/views/dialogs/TransferDialogs/WithdrawDialog2/AmountInput.tsx @@ -1,7 +1,6 @@ -import { EventHandler } from 'react'; - import { BonsaiCore } from '@/bonsai/ontology'; -import { SyntheticInputEvent } from 'react-number-format/types/types'; +import { NumberFormatValues, NumericFormat } from 'react-number-format'; +import styled from 'styled-components'; import { STRING_KEYS } from '@/constants/localization'; import { USDC_DECIMALS } from '@/constants/tokens'; @@ -24,10 +23,6 @@ const TARGET_MARGIN_USAGE_MAX = 0.95; export const AmountInput = ({ value, onChange }: AmountInputProps) => { const stringGetter = useStringGetter(); - const onValueChange: EventHandler = (e) => { - onChange(e.target.value); - }; - const isLoading = useAppSelector(BonsaiCore.account.parentSubaccountSummary.loading) === 'pending'; @@ -87,14 +82,23 @@ export const AmountInput = ({ value, onChange }: AmountInputProps) => { )}
- { + onChange(values.value); + }} /> ); }; + +const $NumericFormat = styled(NumericFormat)` + font: var(--font-large-medium); + background-color: var(--color-layer-4); + color: var(--color-text-2); + outline: none; +`; diff --git a/src/views/dialogs/TransferDialogs/WithdrawDialog2/SpotAmountInput.tsx b/src/views/dialogs/TransferDialogs/WithdrawDialog2/SpotAmountInput.tsx index 2aac2c344..751e21630 100644 --- a/src/views/dialogs/TransferDialogs/WithdrawDialog2/SpotAmountInput.tsx +++ b/src/views/dialogs/TransferDialogs/WithdrawDialog2/SpotAmountInput.tsx @@ -1,5 +1,8 @@ import { Dispatch, SetStateAction } from 'react'; +import { NumberFormatValues, NumericFormat } from 'react-number-format'; +import styled from 'styled-components'; + import { STRING_KEYS } from '@/constants/localization'; import { useStringGetter } from '@/hooks/useStringGetter'; @@ -66,14 +69,23 @@ export const SpotAmountInput = ({ )} - setAmount(e.target.value)} + onValueChange={(values: NumberFormatValues) => { + setAmount(values.value); + }} /> ); }; + +const $NumericFormat = styled(NumericFormat)` + font: var(--font-large-medium); + background-color: var(--color-layer-4); + color: var(--color-text-2); + outline: none; +`; diff --git a/src/views/tables/StakingTierTable.tsx b/src/views/tables/StakingTierTable.tsx index 7dfd32c73..f9398d6c4 100644 --- a/src/views/tables/StakingTierTable.tsx +++ b/src/views/tables/StakingTierTable.tsx @@ -57,7 +57,7 @@ export const StakingTierTable = () => { renderCell: (row: StakingTier) => ( <$TextRow tw="gap-0.5"> - {row.feeTierName === userFeeTier && ( + {row.feeTierName === userFeeTier && currentStakingDiscountLevel != null && ( {stringGetter({ key: STRING_KEYS.YOU })}