From 8463bf48000f0bbf6123a071ed9cedea52d14393 Mon Sep 17 00:00:00 2001 From: Uniswap Labs Service Account Date: Thu, 30 May 2024 23:08:24 +0000 Subject: [PATCH] ci(release): publish latest release --- RELEASE | 54 +- VERSION | 2 +- apps/mobile/.depcheckrc | 1 + apps/mobile/README.md | 16 +- .../src/main/java/com/uniswap/RnEthersRs.kt | 10 +- .../import/SeedPhraseInputViewModel.kt | 4 + .../ios/Uniswap.xcodeproj/project.pbxproj | 18 +- apps/mobile/jest-setup.js | 11 - apps/mobile/package.json | 1 + apps/mobile/src/app/App.tsx | 8 +- apps/mobile/src/app/migrations.test.ts | 27 +- apps/mobile/src/app/migrations.ts | 10 +- .../src/app/modals/AccountSwitcherModal.tsx | 70 +- apps/mobile/src/app/navigation/navigation.tsx | 168 +- apps/mobile/src/app/navigation/types.ts | 2 - apps/mobile/src/app/saga.ts | 12 + apps/mobile/src/app/store.ts | 6 +- .../src/components/PriceExplorer/constants.ts | 5 +- .../components/TokenDetails/TokenBalances.tsx | 2 +- .../Trace/TraceUserProperties.test.tsx | 77 +- .../components/Trace/TraceUserProperties.tsx | 1 + .../WalletConnectRequestModal.tsx | 1 + .../ScanSheet/WalletConnectModal.tsx | 29 +- .../WalletConnect/ScanSheet/util.ts | 2 +- .../__snapshots__/TokenItem.test.tsx.snap | 2 + .../CloudBackupProcessingAnimation.tsx | 46 +- .../src/features/firebase/firebaseDataSaga.ts | 31 +- .../nfts/item/CollectionPreviewCard.tsx | 5 +- apps/mobile/src/features/onboarding/hooks.ts | 87 +- apps/mobile/src/features/telemetry/saga.ts | 13 +- apps/mobile/src/features/telemetry/slice.ts | 1 + .../unitags/ChooseProfilePictureScreen.tsx | 9 +- .../features/unitags/ClaimUnitagScreen.tsx | 13 +- .../walletConnect/signWcRequestSaga.ts | 27 + apps/mobile/src/features/widgets/widgets.ts | 1 + apps/mobile/src/screens/DevScreen.tsx | 15 +- apps/mobile/src/screens/HomeScreen.tsx | 2 +- .../RestoreCloudBackupPasswordScreen.tsx | 15 +- .../screens/Import/SeedPhraseInputScreen.tsx | 24 +- .../Import/SeedPhraseInputScreenV2.tsx | 22 +- .../src/screens/Import/SelectWalletScreen.tsx | 112 +- .../src/screens/Import/WatchWalletScreen.tsx | 37 +- apps/mobile/src/screens/NFTItemScreen.tsx | 20 + .../src/screens/Onboarding/BackupScreen.tsx | 20 +- .../CloudBackupProcessingScreen.tsx | 6 +- .../src/screens/Onboarding/LandingScreen.tsx | 10 +- .../screens/Onboarding/ManualBackupScreen.tsx | 35 +- .../Onboarding/NotificationsSetupScreen.tsx | 23 +- .../Onboarding/WelcomeWalletScreen.tsx | 29 +- .../mobile/src/screens/SettingsWalletEdit.tsx | 149 +- apps/web/.eslintrc.js | 20 +- apps/web/cypress/e2e/remove-liquidity.test.ts | 5 +- apps/web/cypress/e2e/swap/fees.test.ts | 12 +- apps/web/cypress/e2e/swap/uniswapx.test.ts | 10 +- apps/web/cypress/e2e/swap/uniswapxv2.test.ts | 10 +- apps/web/cypress/e2e/token-details.test.ts | 7 +- apps/web/cypress/support/commands.ts | 8 +- apps/web/cypress/support/e2e.ts | 4 +- apps/web/cypress/support/setupTests.ts | 2 +- apps/web/functions/utils/cache.ts | 8 +- apps/web/i18next-parser.config.js | 2 +- apps/web/package.json | 3 +- apps/web/public/nfts-sitemap.xml | 277 +- apps/web/public/pools-sitemap.xml | 2446 ++++++++++++----- apps/web/public/tokens-sitemap.xml | 2225 ++++++++++++--- apps/web/scripts/generate-sitemap.js | 12 +- apps/web/src/analytics/index.tsx | 59 - .../AccountDetails/TransactionSummary.tsx | 265 +- .../AccountDrawer/AnalyticsToggle.tsx | 21 +- .../AccountDrawer/AuthenticatedHeader.tsx | 23 +- .../components/AccountDrawer/DefaultMenu.tsx | 12 +- .../AccountDrawer/GitVersionRow.tsx | 2 +- .../components/AccountDrawer/IconButton.tsx | 8 +- .../components/AccountDrawer/LanguageMenu.tsx | 2 +- .../AccountDrawer/LocalCurrencyMenu.tsx | 6 +- .../MiniPortfolio/Activity/ActivityRow.tsx | 16 +- .../Activity/CancelLimitsDialog.tsx | 24 +- .../Activity/OffchainActivityModal.tsx | 49 +- .../Activity/OffchainOrderLineItem.tsx | 12 +- .../OffchainActivityModal.test.tsx.snap | 22 +- .../MiniPortfolio/Activity/hooks.ts | 20 +- .../MiniPortfolio/Activity/parseLocal.ts | 41 +- .../MiniPortfolio/Activity/parseRemote.tsx | 143 +- .../MiniPortfolio/Activity/utils.ts | 55 +- .../MiniPortfolio/ExpandoRow.tsx | 8 +- .../Limits/LimitDetailActivityRow.tsx | 30 +- .../MiniPortfolio/Limits/LimitsMenu.tsx | 6 +- .../Limits/OpenLimitOrdersButton.tsx | 18 +- .../MiniPortfolio/NFTs/NFTItem.tsx | 4 +- .../MiniPortfolio/NFTs/index.tsx | 3 +- .../MiniPortfolio/Pools/getTokensAsync.ts | 12 +- .../MiniPortfolio/Pools/hooks.ts | 8 +- .../MiniPortfolio/Pools/index.tsx | 24 +- .../Pools/useMultiChainPositions.tsx | 9 +- .../MiniPortfolio/PortfolioLogo.tsx | 4 +- .../MiniPortfolio/Tokens/index.tsx | 22 +- .../AccountDrawer/MiniPortfolio/constants.tsx | 254 +- .../AccountDrawer/MiniPortfolio/index.tsx | 38 +- .../components/AccountDrawer/SettingsMenu.tsx | 10 +- .../AccountDrawer/SmallBalanceToggle.tsx | 2 +- .../components/AccountDrawer/SpamToggle.tsx | 2 +- .../AccountDrawer/TestnetsToggle.tsx | 2 +- .../AccountDrawer/UniwalletModal.tsx | 16 +- .../src/components/AccountDrawer/index.tsx | 17 +- .../src/components/AccountDrawer/shared.tsx | 4 +- .../components/AddressInputPanel/index.tsx | 10 +- apps/web/src/components/Badge/RangeBadge.tsx | 24 +- .../components/Banner/Outage/OutageBanner.tsx | 11 +- .../src/components/BreadcrumbNav/index.tsx | 6 +- apps/web/src/components/Button/GetHelp.tsx | 4 +- apps/web/src/components/Charts/ChartModel.tsx | 10 +- .../Charts/LiquidityChart/index.tsx | 4 +- .../Charts/LiquidityChart/renderer.tsx | 4 +- .../src/components/Charts/LoadingState.tsx | 2 +- .../rounded-candles-series.ts | 4 +- .../components/Charts/PriceChart/index.tsx | 8 +- .../src/components/Charts/PriceChart/utils.ts | 8 +- .../stacked-area-series/renderer.ts | 8 +- .../CrosshairHighlightPrimitive.tsx | 12 +- .../components/Charts/VolumeChart/index.tsx | 14 +- .../Charts/VolumeChart/renderer.tsx | 4 +- .../components/Charts/VolumeChart/utils.ts | 16 +- apps/web/src/components/Charts/hooks.ts | 4 +- apps/web/src/components/Charts/utils.tsx | 12 +- .../ConfirmSwapModal/Error.test.tsx | 2 +- .../src/components/ConfirmSwapModal/Error.tsx | 62 +- .../src/components/ConfirmSwapModal/Head.tsx | 2 +- .../src/components/ConfirmSwapModal/Modal.tsx | 2 +- .../components/ConfirmSwapModal/Pending.tsx | 36 +- .../ConfirmSwapModal/ProgressIndicator.tsx | 42 +- .../__snapshots__/Error.test.tsx.snap | 1858 +++++++------ .../__snapshots__/Head.test.tsx.snap | 56 +- .../src/components/ConfirmSwapModal/index.tsx | 50 +- .../ConnectedAccountBlocked/index.tsx | 8 +- .../CurrencyInputPanel/FiatValue.tsx | 22 +- .../LimitPriceInputPanel/LimitPriceButton.tsx | 4 +- .../LimitPriceInputLabel.tsx | 6 +- .../LimitPriceInputPanel.test.tsx | 9 +- .../LimitPriceInputPanel.tsx | 42 +- .../SwapCurrencyInputPanel.tsx | 35 +- .../components/CurrencyInputPanel/index.tsx | 31 +- apps/web/src/components/Dialog/Dialog.tsx | 14 +- .../Dialog/__snapshots__/Dialog.test.tsx.snap | 296 +- apps/web/src/components/DoubleLogo/index.tsx | 4 +- .../src/components/ErrorBoundary/index.tsx | 26 +- .../FeatureFlagModal/FeatureFlagModal.tsx | 5 +- .../FeeSelector/FeeTierPercentageBadge.tsx | 6 +- apps/web/src/components/FeeSelector/index.tsx | 19 +- .../web/src/components/FeeSelector/shared.tsx | 8 +- .../components/FiatOnrampModal/constants.ts | 2 + .../src/components/FiatOnrampModal/index.tsx | 6 +- .../src/components/FiatOnrampModal/utils.ts | 4 +- .../components/Icons/AlertTriangleFilled.tsx | 13 +- .../components/Identicon/StatusIcon.test.tsx | 8 +- .../src/components/Identicon/StatusIcon.tsx | 7 +- .../__snapshots__/StatusIcon.test.tsx.snap | 36 +- apps/web/src/components/Identicon/index.tsx | 45 +- .../InputStepCounter/InputStepCounter.tsx | 4 +- .../LiquidityChartRangeInput/Brush.tsx | 8 +- .../LiquidityChartRangeInput/Zoom.tsx | 4 +- .../LiquidityChartRangeInput/index.tsx | 21 +- apps/web/src/components/Logo/ChainLogo.tsx | 8 +- .../src/components/Logo/HolidayUniIcon.tsx | 2 +- .../src/components/Logo/UniswapXBrandMark.tsx | 2 +- apps/web/src/components/ModalViews/index.tsx | 8 +- .../src/components/NavBar/ChainSelector.tsx | 30 +- .../components/NavBar/ChainSelectorRow.tsx | 27 +- .../NavBar/MobileAppPromoBanner.tsx | 129 + apps/web/src/components/NavBar/More/Menu.tsx | 4 +- apps/web/src/components/NavBar/NavIcon.tsx | 2 +- .../NavBar/RecentlySearchedAssets.ts | 15 +- apps/web/src/components/NavBar/SearchBar.tsx | 33 +- .../components/NavBar/SearchBarDropdown.tsx | 30 +- .../src/components/NavBar/SuggestionRow.tsx | 24 +- apps/web/src/components/NavBar/UkBanner.tsx | 14 +- .../components/NavBar/UkDisclaimerModal.tsx | 4 +- apps/web/src/components/NavBar/index.tsx | 12 +- .../src/components/NavigationTabs/index.tsx | 34 +- .../components/NetworkAlert/NetworkAlert.tsx | 20 +- .../src/components/NumericalInput/index.tsx | 8 +- .../Polling/ChainConnectivityWarning.tsx | 20 +- apps/web/src/components/Polling/index.tsx | 14 +- .../Pools/PoolDetails/ChartSection/index.tsx | 32 +- .../Pools/PoolDetails/PoolDetailsHeader.tsx | 10 +- .../Pools/PoolDetails/PoolDetailsLink.tsx | 4 +- .../PoolDetails/PoolDetailsPositionsTable.tsx | 16 +- .../PoolDetails/PoolDetailsStats.test.tsx | 4 +- .../Pools/PoolDetails/PoolDetailsStats.tsx | 21 +- .../PoolDetailsStatsButtons.test.tsx | 8 +- .../PoolDetails/PoolDetailsStatsButtons.tsx | 34 +- .../Pools/PoolDetails/PoolDetailsTable.tsx | 4 +- .../PoolDetailsTransactionsTable.tsx | 19 +- .../PoolDetailsStatsButtons.test.tsx.snap | 9 +- .../PoolDetailsTransactionTable.test.tsx.snap | 2 +- .../components/Pools/PoolTable/PoolTable.tsx | 19 +- .../__snapshots__/PoolTable.test.tsx.snap | 34 +- apps/web/src/components/Popups/ClaimPopup.tsx | 13 +- .../src/components/Popups/PopupContent.tsx | 12 +- apps/web/src/components/Popups/PopupItem.tsx | 8 +- .../components/Popups/UniconV2InfoPopup.tsx | 2 +- .../web/src/components/PositionCard/Sushi.tsx | 4 +- apps/web/src/components/PositionCard/V2.tsx | 22 +- .../web/src/components/PositionCard/index.tsx | 47 +- .../web/src/components/PositionList/index.tsx | 8 +- .../PositionListItem.test.tsx | 4 +- .../src/components/PositionListItem/index.tsx | 26 +- .../src/components/PositionPreview/index.tsx | 33 +- .../src/components/PrivacyPolicy/index.tsx | 36 +- .../RangeSelector/PresetsButtons.tsx | 2 +- .../src/components/RangeSelector/index.tsx | 4 +- .../RoutingDiagram/RoutingDiagram.tsx | 7 +- .../components/SearchModal/CommonBases.tsx | 14 +- .../SearchModal/CurrencyList/index.tsx | 25 +- .../components/SearchModal/CurrencySearch.tsx | 23 +- .../SearchModal/useCurrencySearchResults.ts | 16 +- .../Settings/MaxSlippageSettings/index.tsx | 23 +- .../components/Settings/MenuButton/index.tsx | 6 +- .../Settings/MultipleRoutingOptions.test.tsx | 9 + .../Settings/MultipleRoutingOptions.tsx | 16 +- .../RouterPreferenceSettings/index.tsx | 2 +- .../TransactionDeadlineSettings/index.tsx | 10 +- .../src/components/Settings/index.test.tsx | 7 +- apps/web/src/components/Settings/index.tsx | 6 +- .../src/components/SwitchLocaleLink/index.tsx | 6 +- apps/web/src/components/Table/index.tsx | 22 +- apps/web/src/components/Table/styled.tsx | 2 +- apps/web/src/components/Table/utils.ts | 2 +- apps/web/src/components/Toggle/index.tsx | 4 +- .../TokenSafety/TokenSafetyMessage.tsx | 8 +- apps/web/src/components/TokenSafety/index.tsx | 10 +- .../Tokens/TokenDetails/ActivitySection.tsx | 4 +- .../Tokens/TokenDetails/BalanceSummary.tsx | 14 +- .../ChartSection/AdvancedPriceChartToggle.tsx | 2 +- .../ChartSection/ChartTypeSelector.tsx | 6 +- .../Tokens/TokenDetails/ChartSection/hooks.ts | 8 +- .../TokenDetails/ChartSection/index.tsx | 6 +- .../Tokens/TokenDetails/ChartSection/util.ts | 4 +- .../components/Tokens/TokenDetails/Delta.tsx | 4 +- .../TokenDetails/InvalidTokenDetails.tsx | 15 +- .../MobileBalanceSummaryFooter.tsx | 4 +- .../Tokens/TokenDetails/ShareButton.tsx | 6 +- .../Tokens/TokenDetails/Skeleton.tsx | 13 +- .../Tokens/TokenDetails/StatsSection.tsx | 46 +- .../Tokens/TokenDetails/TokenDescription.tsx | 31 +- .../TokenDetails/TokenDetailsHeader.tsx | 35 +- .../components/Tokens/TokenDetails/index.tsx | 16 +- .../TokenDetails/tables/TransactionsTable.tsx | 10 +- .../TokenDetailsPoolsTable.test.tsx.snap | 104 +- .../Tokens/TokenTable/NetworkFilter.tsx | 30 +- .../Tokens/TokenTable/SearchBar.tsx | 21 +- .../Tokens/TokenTable/TimeSelector.tsx | 4 +- .../components/Tokens/TokenTable/icons.tsx | 36 + .../components/Tokens/TokenTable/index.tsx | 24 +- .../TransactionConfirmationModal/index.tsx | 53 +- apps/web/src/components/Unicon/index.tsx | 8 +- apps/web/src/components/Unicon/utils.ts | 4 +- .../src/components/V2Unsupported/index.tsx | 2 +- .../WalletModal/ConnectionErrorView.tsx | 14 +- .../web/src/components/WalletModal/Option.tsx | 18 +- .../WalletModal/PrivacyPolicyNotice.tsx | 8 +- .../WalletModal/UniswapWalletOptions.tsx | 8 +- apps/web/src/components/WalletModal/index.tsx | 4 +- .../WalletModal/useOrderedConnections.tsx | 26 +- .../components/Web3Provider/index.test.tsx | 25 +- .../web/src/components/Web3Provider/index.tsx | 29 +- apps/web/src/components/Web3Provider/wagmi.ts | 64 +- apps/web/src/components/Web3Status/index.tsx | 27 +- .../Web3Status/useAccountIdentifier.ts | 15 +- .../addLiquidity/OutOfSyncWarning.tsx | 9 +- .../addLiquidity/OwnershipWarning.tsx | 7 +- .../components/addLiquidity/PoolWarning.tsx | 2 +- .../addLiquidity/TokenTaxV3Warning.tsx | 9 +- apps/web/src/components/analytics/index.ts | 2 +- .../components/claim/AddressClaimModal.tsx | 31 +- .../src/components/swap/DetailLineItem.tsx | 8 +- .../components/swap/GasBreakdownTooltip.tsx | 41 +- .../components/swap/GasEstimateTooltip.tsx | 7 +- .../src/components/swap/LimitDisclaimer.tsx | 7 +- .../components/swap/MaxSlippageTooltip.tsx | 14 +- .../src/components/swap/PriceImpactModal.tsx | 23 +- .../components/swap/PriceImpactWarning.tsx | 11 +- .../src/components/swap/SwapBuyFiatButton.tsx | 26 +- apps/web/src/components/swap/SwapDetails.tsx | 34 +- .../components/swap/SwapDetailsDropdown.tsx | 22 +- .../src/components/swap/SwapHeader.test.tsx | 3 +- apps/web/src/components/swap/SwapHeader.tsx | 18 +- apps/web/src/components/swap/SwapLineItem.tsx | 109 +- apps/web/src/components/swap/SwapPreview.tsx | 26 +- apps/web/src/components/swap/SwapRoute.tsx | 13 +- apps/web/src/components/swap/SwapSkeleton.tsx | 2 +- .../swap/UnsupportedCurrencyFooter.tsx | 13 +- apps/web/src/components/swap/constants.ts | 6 - .../web/src/components/vote/DelegateModal.tsx | 16 +- apps/web/src/components/vote/ExecuteModal.tsx | 22 +- .../components/vote/ProposalEmptyState.tsx | 17 +- apps/web/src/components/vote/QueueModal.tsx | 22 +- apps/web/src/components/vote/VoteModal.tsx | 30 +- apps/web/src/connection/activate.ts | 2 +- apps/web/src/connection/web3reactShim.ts | 9 +- apps/web/src/constants/chains.test.ts | 12 + apps/web/src/constants/chains.ts | 1303 +++++---- apps/web/src/constants/providers.ts | 2 +- apps/web/src/constants/tokenSafety.tsx | 22 +- apps/web/src/constants/tokens.ts | 33 +- .../src/featureFlags/flags/outageBanner.ts | 8 +- apps/web/src/graphql/data/SearchTokens.ts | 48 +- apps/web/src/graphql/data/TopTokens.ts | 20 +- .../graphql/data/apollo/AdaptiveRefetch.tsx | 20 +- .../data/apollo/AssetActivityProvider.tsx | 4 +- .../data/apollo/TokenBalancesProvider.tsx | 10 +- apps/web/src/graphql/data/nft/Collection.ts | 4 +- .../data/nft/NftUniversalRouterAddress.ts | 4 +- .../graphql/data/pools/usePoolTransactions.ts | 8 +- .../data/pools/usePoolsFromTokenAddress.ts | 16 +- .../web/src/graphql/data/pools/useTopPools.ts | 4 +- .../src/graphql/data/useAllTransactions.ts | 12 +- .../src/graphql/data/useTokenTransactions.ts | 16 +- apps/web/src/graphql/data/util.test.tsx | 12 +- apps/web/src/graphql/data/util.tsx | 45 +- apps/web/src/hooks/Tokens.ts | 34 +- apps/web/src/hooks/useAccount.ts | 27 + apps/web/src/hooks/useAccountRiskCheck.ts | 4 +- apps/web/src/hooks/useActiveLocalCurrency.ts | 4 +- apps/web/src/hooks/useActiveLocale.ts | 17 +- apps/web/src/hooks/useAutoRouterSupported.tsx | 7 +- .../web/src/hooks/useAutoSlippageTolerance.ts | 8 +- apps/web/src/hooks/useConfirmModalState.ts | 14 +- apps/web/src/hooks/useContract.ts | 38 +- apps/web/src/hooks/useDebouncedTrade.ts | 8 +- apps/web/src/hooks/useDisableScrolling.ts | 4 +- apps/web/src/hooks/useENSAvatar.ts | 4 +- apps/web/src/hooks/useENSName.ts | 4 +- apps/web/src/hooks/useERC20Permit.ts | 34 +- apps/web/src/hooks/useEthersProvider.ts | 23 +- apps/web/src/hooks/useEthersSigner.ts | 15 +- .../useFilterPossiblyMaliciousPositions.ts | 36 +- apps/web/src/hooks/useGlobalChainSwitch.ts | 4 +- apps/web/src/hooks/useIsWindowVisible.ts | 4 +- apps/web/src/hooks/useLast.ts | 4 +- .../src/hooks/useLocalCurrencyLinkProps.ts | 6 +- apps/web/src/hooks/useNetworkSupportsV2.ts | 10 +- apps/web/src/hooks/useOnClickOutside.ts | 4 +- apps/web/src/hooks/usePermit2Allowance.ts | 12 +- apps/web/src/hooks/usePermitAllowance.ts | 25 +- apps/web/src/hooks/usePools.ts | 52 +- apps/web/src/hooks/usePositionTokenURI.ts | 3 +- apps/web/src/hooks/useSendCallback.ts | 22 +- apps/web/src/hooks/useStablecoinPrice.ts | 14 +- apps/web/src/hooks/useSwapCallback.tsx | 16 +- apps/web/src/hooks/useSwapTaxes.ts | 13 +- apps/web/src/hooks/useSwitchChain.ts | 4 +- apps/web/src/hooks/useSyncChainQuery.ts | 11 +- apps/web/src/hooks/useTokenAllowance.ts | 17 +- apps/web/src/hooks/useTokenBalances.ts | 13 +- apps/web/src/hooks/useTransactionDeadline.ts | 14 +- apps/web/src/hooks/useUSDTokenUpdater.ts | 4 +- apps/web/src/hooks/useUniswapXSwapCallback.ts | 26 +- apps/web/src/hooks/useUniversalRouter.ts | 29 +- apps/web/src/hooks/useUnmountingAnimation.ts | 4 +- apps/web/src/hooks/useV2Pairs.ts | 12 +- apps/web/src/hooks/useWrapCallback.tsx | 34 +- apps/web/src/i18n.tsx | 81 +- apps/web/src/i18n/LanguageProvider.tsx | 18 + apps/web/src/i18n/Plural.tsx | 10 + apps/web/src/i18n/Trans.tsx | 8 + apps/web/src/i18n/dynamicActivate.tsx | 15 + apps/web/src/i18n/initialLocale.ts | 6 + apps/web/src/i18n/locales/source/en-US.json | 2094 +++++++------- apps/web/src/i18n/useTranslation.tsx | 10 + apps/web/src/index.tsx | 5 +- apps/web/src/lib/hooks/multicall.ts | 4 +- .../routing/clientSideSmartOrderRouter.ts | 8 +- .../hooks/routing/useRoutingAPIArguments.ts | 24 +- apps/web/src/lib/hooks/useApproval.ts | 18 +- apps/web/src/lib/hooks/useCurrencyBalance.ts | 27 +- apps/web/src/lib/hooks/useCurrencyLogoURIs.ts | 4 +- apps/web/src/lib/hooks/useInterval.ts | 4 +- .../src/lib/hooks/useTokenList/filtering.ts | 4 +- .../web/src/lib/hooks/useTokenList/sorting.ts | 6 +- apps/web/src/lib/hooks/useTokenList/utils.ts | 4 +- apps/web/src/lib/state/multicall.tsx | 4 +- apps/web/src/lib/utils/analytics.ts | 16 +- apps/web/src/lib/utils/contenthashToUri.ts | 4 +- apps/web/src/lib/utils/parseENSAddress.ts | 4 +- apps/web/src/nft/components/bag/Bag.tsx | 11 +- .../web/src/nft/components/bag/BagContent.tsx | 21 +- apps/web/src/nft/components/bag/BagFooter.tsx | 28 +- apps/web/src/nft/components/bag/BagHeader.tsx | 6 +- apps/web/src/nft/components/bag/BagRow.tsx | 4 +- .../src/nft/components/bag/ButtonStates.tsx | 48 +- apps/web/src/nft/components/card/icons.tsx | 2 +- apps/web/src/nft/components/card/index.tsx | 4 +- apps/web/src/nft/components/card/media.tsx | 4 +- apps/web/src/nft/components/card/utils.tsx | 8 +- .../components/collection/ActivityCells.tsx | 24 +- .../collection/ActivitySwitcher.tsx | 13 +- .../components/collection/CollectionAsset.tsx | 9 +- .../components/collection/CollectionNfts.tsx | 43 +- .../collection/MarketplaceSelect.tsx | 5 +- .../nft/components/collection/PriceRange.tsx | 9 +- .../src/nft/components/collection/Sweep.tsx | 33 +- .../nft/components/collection/TraitSelect.tsx | 3 +- .../collection/TransactionCompleteModal.tsx | 24 +- .../collection/UnavailableCollectionPage.tsx | 10 +- .../nft/components/details/AssetActivity.tsx | 14 +- .../components/details/AssetPriceDetails.tsx | 3 +- .../web/src/nft/components/explore/Banner.tsx | 4 +- .../nft/components/explore/CarouselCard.tsx | 4 +- .../nft/components/explore/Cells/Cells.tsx | 8 +- .../components/explore/CollectionTable.tsx | 8 +- apps/web/src/nft/components/explore/Table.tsx | 21 +- .../explore/TrendingCollections.tsx | 4 +- .../nft/components/profile/list/ListPage.tsx | 22 +- .../components/profile/list/ListingButton.tsx | 23 +- .../profile/list/MarketplaceRow.tsx | 6 +- .../list/Modal/BelowFloorWarningModal.tsx | 14 +- .../profile/list/Modal/ContentRow.tsx | 12 +- .../profile/list/Modal/ListModal.tsx | 15 +- .../profile/list/Modal/ListModalSection.tsx | 21 +- .../profile/list/Modal/SuccessScreen.tsx | 13 +- .../profile/list/NFTListingsGrid.tsx | 20 +- .../profile/list/PriceTextInput.tsx | 10 +- .../profile/list/RoyaltyTooltip.tsx | 6 +- .../list/SelectMarketplacesDropdown.tsx | 4 +- .../profile/list/SetDurationModal.tsx | 18 +- .../src/nft/components/profile/list/utils.ts | 28 +- .../profile/view/EmptyWalletContent.tsx | 22 +- .../components/profile/view/FilterSidebar.tsx | 4 +- .../components/profile/view/ProfilePage.tsx | 8 +- .../profile/view/ViewMyNftsAsset.tsx | 16 +- apps/web/src/nft/css/atoms.ts | 4 +- apps/web/src/nft/hooks/useBag.ts | 41 +- apps/web/src/nft/hooks/usePurchaseAssets.ts | 4 +- apps/web/src/nft/hooks/useSellAsset.ts | 25 +- apps/web/src/nft/hooks/useSendTransaction.ts | 2 +- .../nft/hooks/useSubscribeTransactionState.ts | 8 +- .../web/src/nft/hooks/useWalletCollections.ts | 15 +- apps/web/src/nft/pages/asset/Asset.tsx | 10 +- apps/web/src/nft/pages/collection/index.tsx | 20 +- apps/web/src/nft/pages/explore/index.tsx | 4 +- apps/web/src/nft/pages/profile/index.tsx | 17 +- .../queries/openSea/OSCollectionsFetcher.ts | 8 +- apps/web/src/nft/types/common/index.ts | 4 +- apps/web/src/nft/utils/buildSellObject.ts | 4 +- apps/web/src/nft/utils/collection.ts | 12 +- apps/web/src/nft/utils/date.ts | 12 +- apps/web/src/nft/utils/isAudio.ts | 4 +- apps/web/src/nft/utils/listNfts.ts | 32 +- apps/web/src/nft/utils/numbers.ts | 8 +- apps/web/src/nft/utils/pooledAssets.ts | 31 +- apps/web/src/nft/utils/transactionResponse.ts | 4 +- .../utils/txRoute/combineItemsWithTxRoute.ts | 4 +- apps/web/src/nft/utils/updatedAssets.ts | 4 +- apps/web/src/nft/utils/urlParams.ts | 7 +- .../src/pages/AddLiquidity/blastAlerts.tsx | 22 +- apps/web/src/pages/AddLiquidity/index.tsx | 143 +- apps/web/src/pages/AddLiquidity/redirects.tsx | 4 +- .../AddLiquidityV2/ConfirmAddModalBottom.tsx | 15 +- .../src/pages/AddLiquidityV2/PoolPriceBar.tsx | 16 +- apps/web/src/pages/AddLiquidityV2/index.tsx | 99 +- apps/web/src/pages/App.tsx | 55 +- .../CreateProposal/ProposalActionDetail.tsx | 4 +- .../CreateProposal/ProposalActionSelector.tsx | 8 +- .../pages/CreateProposal/ProposalEditor.tsx | 4 +- .../ProposalSubmissionModal.tsx | 8 +- apps/web/src/pages/CreateProposal/index.tsx | 50 +- .../Explore/charts/ExploreChartsSection.tsx | 18 +- apps/web/src/pages/Explore/index.tsx | 31 +- .../Explore/tables/RecentTransactions.tsx | 16 +- apps/web/src/pages/Landing/Fold.tsx | 6 +- .../DownloadApp/GetTheAppButton.tsx | 2 +- .../components/DownloadApp/GetTheAppModal.tsx | 4 +- .../components/cards/DocumentationCard.tsx | 4 +- .../components/cards/DownloadWalletCard.tsx | 4 +- .../components/cards/LiquidityCard.tsx | 6 +- .../Landing/components/cards/WebappCard.tsx | 4 +- apps/web/src/pages/Landing/index.tsx | 4 +- .../pages/Landing/sections/DirectToDefi.tsx | 2 +- .../web/src/pages/Landing/sections/Footer.tsx | 32 +- apps/web/src/pages/Landing/sections/Hero.tsx | 13 +- .../pages/Landing/sections/NewsletterEtc.tsx | 18 +- apps/web/src/pages/Landing/sections/Stats.tsx | 23 +- .../src/pages/Landing/sections/useInView.tsx | 4 +- .../web/src/pages/MigrateV2/MigrateV2Pair.tsx | 143 +- apps/web/src/pages/MigrateV2/index.tsx | 32 +- apps/web/src/pages/NotFound/index.tsx | 9 +- apps/web/src/pages/Pool/CTACards.tsx | 12 +- apps/web/src/pages/Pool/PositionPage.tsx | 113 +- apps/web/src/pages/Pool/index.tsx | 36 +- apps/web/src/pages/Pool/shared.tsx | 10 +- apps/web/src/pages/Pool/v2.tsx | 43 +- apps/web/src/pages/PoolDetails/index.tsx | 10 +- apps/web/src/pages/PoolDetails/utils.ts | 2 +- apps/web/src/pages/PoolFinder/index.tsx | 41 +- apps/web/src/pages/RemoveLiquidity/V3.tsx | 115 +- apps/web/src/pages/RemoveLiquidity/index.tsx | 130 +- apps/web/src/pages/RouteDefinitions.tsx | 62 +- .../Swap/Limit/LimitExpirySection.test.tsx | 5 +- .../pages/Swap/Limit/LimitExpirySection.tsx | 35 +- apps/web/src/pages/Swap/Limit/LimitForm.tsx | 92 +- .../src/pages/Swap/Limit/LimitPriceError.tsx | 28 +- .../LimitPriceError.test.tsx.snap | 4 +- .../pages/Swap/Send/NewAddressSpeedBump.tsx | 13 +- .../Swap/Send/SendCurrencyInputForm.test.tsx | 2 +- .../pages/Swap/Send/SendCurrencyInputForm.tsx | 37 +- apps/web/src/pages/Swap/Send/SendForm.tsx | 40 +- .../Swap/Send/SendRecipientForm.test.tsx | 2 +- .../src/pages/Swap/Send/SendRecipientForm.tsx | 9 +- .../pages/Swap/Send/SendReviewModal.test.tsx | 2 +- .../src/pages/Swap/Send/SendReviewModal.tsx | 14 +- .../Swap/Send/SmartContractSpeedBump.tsx | 13 +- .../NewAddressSpeedBump.test.tsx.snap | 618 +++-- .../SendCurrencyInputForm.test.tsx.snap | 6 +- .../SendRecipientForm.test.tsx.snap | 202 +- .../SendReviewModal.test.tsx.snap | 242 +- .../SmartContractSpeedbump.test.tsx.snap | 136 +- apps/web/src/pages/Swap/SwapForm.tsx | 110 +- apps/web/src/pages/Swap/TaxTooltipBody.tsx | 10 +- apps/web/src/pages/Swap/index.tsx | 18 +- .../web/src/pages/TokenDetails/TDPContext.tsx | 4 +- apps/web/src/pages/TokenDetails/index.tsx | 30 +- apps/web/src/pages/TokenDetails/utils.ts | 2 +- apps/web/src/pages/Vote/Landing.tsx | 60 +- apps/web/src/pages/Vote/VotePage.tsx | 86 +- apps/web/src/pages/Vote/styled.tsx | 18 +- apps/web/src/pages/metatags.ts | 2 +- apps/web/src/pages/paths.test.ts | 4 +- apps/web/src/rpc/AppJsonRpcProvider.ts | 4 +- apps/web/src/setupTests.ts | 4 +- apps/web/src/state/activity/polling/orders.ts | 8 +- apps/web/src/state/activity/polling/retry.ts | 4 +- .../state/activity/polling/transactions.ts | 32 +- apps/web/src/state/activity/subscription.ts | 8 +- apps/web/src/state/activity/updater.tsx | 6 +- apps/web/src/state/application/atoms.ts | 1 + apps/web/src/state/application/hooks.ts | 16 +- apps/web/src/state/burn/hooks.tsx | 4 +- apps/web/src/state/burn/v3/hooks.tsx | 4 +- apps/web/src/state/claim/hooks.ts | 28 +- apps/web/src/state/governance/hooks.ts | 49 +- apps/web/src/state/limit/LimitContext.tsx | 6 +- .../state/limit/expiryToDeadlineSeconds.ts | 12 +- apps/web/src/state/limit/hooks.ts | 36 +- apps/web/src/state/limit/types.ts | 10 +- apps/web/src/state/lists/hooks.ts | 8 +- apps/web/src/state/lists/reducer.ts | 4 +- apps/web/src/state/lists/tokenFromList.ts | 16 +- apps/web/src/state/lists/updater.ts | 12 +- apps/web/src/state/logs/hooks.ts | 11 +- apps/web/src/state/logs/slice.ts | 42 +- apps/web/src/state/logs/updater.ts | 36 +- apps/web/src/state/logs/utils.ts | 16 +- apps/web/src/state/migrations/10.ts | 4 +- apps/web/src/state/migrations/11.ts | 4 +- apps/web/src/state/migrations/12.ts | 4 +- apps/web/src/state/migrations/5.ts | 4 +- apps/web/src/state/migrations/6.ts | 4 +- apps/web/src/state/migrations/7.ts | 4 +- apps/web/src/state/migrations/8.ts | 4 +- apps/web/src/state/migrations/9.ts | 4 +- apps/web/src/state/mint/hooks.tsx | 24 +- apps/web/src/state/mint/v3/hooks.tsx | 28 +- apps/web/src/state/routing/gas.ts | 20 +- apps/web/src/state/routing/quickRouteSlice.ts | 6 +- apps/web/src/state/routing/slice.ts | 30 +- apps/web/src/state/routing/types.ts | 42 +- apps/web/src/state/routing/usePreviewTrade.ts | 8 +- .../state/routing/useRoutingAPITrade.test.ts | 23 + apps/web/src/state/routing/utils.test.ts | 4 + apps/web/src/state/routing/utils.ts | 25 +- apps/web/src/state/signatures/hooks.ts | 7 +- apps/web/src/state/signatures/reducer.ts | 12 +- apps/web/src/state/stake/hooks.tsx | 4 +- apps/web/src/state/swap/SwapContext.test.tsx | 6 +- apps/web/src/state/swap/SwapContext.tsx | 9 +- apps/web/src/state/swap/hooks.test.ts | 227 +- apps/web/src/state/swap/hooks.tsx | 126 +- apps/web/src/state/swap/types.ts | 5 +- .../web/src/state/transactions/hooks.test.tsx | 11 +- apps/web/src/state/transactions/hooks.tsx | 28 +- apps/web/src/state/transactions/reducer.ts | 4 +- apps/web/src/state/user/hooks.tsx | 34 +- apps/web/src/state/user/userAddedTokens.ts | 4 +- apps/web/src/state/wallets/reducer.ts | 4 +- apps/web/src/test-utils/constants.ts | 4 +- apps/web/src/test-utils/mocked.tsx | 4 +- apps/web/src/test-utils/tokens/mocks.ts | 132 +- .../components/DarkModeQueryParamReader.tsx | 12 +- .../web/src/theme/components/FadePresence.tsx | 2 +- .../RadialGradientByChainUpdater.ts | 4 +- apps/web/src/theme/components/ThemeToggle.tsx | 8 +- apps/web/src/theme/components/index.tsx | 2 +- apps/web/src/theme/index.tsx | 9 +- .../src/tracing/SwapEventTimestampTracker.ts | 8 +- apps/web/src/tracing/errors.ts | 40 +- apps/web/src/tracing/index.ts | 32 +- apps/web/src/tracing/swapFlowLoggers.test.ts | 6 +- apps/web/src/tracing/swapFlowLoggers.ts | 6 +- apps/web/src/tracing/trace.ts | 24 +- apps/web/src/utils/addressesAreEquivalent.ts | 4 +- apps/web/src/utils/approveAmountCalldata.ts | 4 +- apps/web/src/utils/arrays.ts | 4 +- apps/web/src/utils/calculateSlippageAmount.ts | 4 +- .../src/utils/computeFiatValuePriceImpact.tsx | 8 +- apps/web/src/utils/currencyId.ts | 8 +- apps/web/src/utils/currencyKey.ts | 8 +- apps/web/src/utils/env.ts | 8 +- apps/web/src/utils/errors.ts | 6 +- apps/web/src/utils/formatNumbers.ts | 27 +- apps/web/src/utils/getInitialLogoURL.ts | 4 +- ...pportedChainIdsFromWalletConnectSession.ts | 4 +- apps/web/src/utils/loggingFormatters.ts | 8 +- apps/web/src/utils/maxAmountSpend.ts | 4 +- apps/web/src/utils/nativeTokens.ts | 4 +- apps/web/src/utils/openDownloadApp.ts | 2 +- apps/web/src/utils/prices.ts | 20 +- apps/web/src/utils/safeNamehash.ts | 4 +- apps/web/src/utils/signing.test.ts | 24 +- .../utils/swapErrorToUserReadableMessage.tsx | 4 +- apps/web/src/utils/unwrappedToken.ts | 8 +- apps/web/src/utils/urlChecks.ts | 4 +- apps/web/src/utils/walletMeta.ts | 4 +- dangerfile.ts | 63 +- package.json | 1 + .../__snapshots__/preset.test.ts.snap | 10 +- packages/eslint-config/base.js | 1 + packages/eslint-config/react.js | 1 + packages/eslint-config/restrictedImports.js | 9 + packages/ui/src/assets/index.ts | 1 + .../ui/src/assets/logos/png/zora-logo.png | Bin 0 -> 148082 bytes packages/ui/src/theme/color/colors.ts | 2 + packages/ui/src/theme/color/types.ts | 1 + packages/uniswap/package.json | 26 +- packages/uniswap/src/constants/urls.ts | 2 + packages/uniswap/src/data/cache.ts | 2 +- .../graphql/uniswap-data-api/queries.graphql | 10 + .../graphql/uniswap-data-api/schema.graphql | 3 + .../uniswap-data-api/web/token.graphql | 1 + .../src/features/gating/experiments.ts | 49 +- packages/uniswap/src/features/gating/flags.ts | 4 +- packages/uniswap/src/features/gating/hooks.ts | 64 +- .../uniswap/src/features/telemetry/Trace.tsx | 25 +- .../src/features/telemetry/constants/index.ts | 1 + .../features/telemetry/constants/interface.ts | 15 + .../src/features/telemetry/constants/trace.ts | 41 +- .../src/features/telemetry/send.native.ts | 9 +- .../src/features/telemetry/send.web.ts | 1 + .../uniswap/src/features/telemetry/types.ts | 351 ++- .../uniswap/src/features/telemetry/user.ts | 9 +- .../src/i18n/locales/source/en-US.json | 23 +- .../src/i18n/locales/translations/es-ES.json | 26 +- .../src/i18n/locales/translations/fr-FR.json | 28 +- .../src/i18n/locales/translations/hi-IN.json | 28 +- .../src/i18n/locales/translations/id-ID.json | 28 +- .../src/i18n/locales/translations/ja-JP.json | 28 +- .../src/i18n/locales/translations/ms-MY.json | 26 +- .../src/i18n/locales/translations/nl-NL.json | 28 +- .../src/i18n/locales/translations/pt-PT.json | 28 +- .../src/i18n/locales/translations/ru-RU.json | 28 +- .../src/i18n/locales/translations/th-TH.json | 26 +- .../src/i18n/locales/translations/tr-TR.json | 28 +- .../src/i18n/locales/translations/uk-UA.json | 26 +- .../src/i18n/locales/translations/ur-PK.json | 26 +- .../src/i18n/locales/translations/vi-VN.json | 26 +- .../src/i18n/locales/translations/zh-CN.json | 26 +- .../src/i18n/locales/translations/zh-TW.json | 28 +- packages/uniswap/src/types/chains.ts | 1 + packages/uniswap/src/types/limits.ts | 6 + packages/uniswap/src/types/quote.ts | 4 - .../uniswap/src/types/screens/interface.ts | 5 + packages/uniswap/src/types/walletConnect.ts | 1 + packages/uniswap/src/types/wrap.ts | 6 + packages/utilities/package.json | 2 + packages/utilities/src/logger/logger.ts | 36 +- .../analytics/ApplicationTransport.ts | 41 +- .../telemetry/analytics/analytics.native.ts | 21 +- .../src/telemetry/analytics/analytics.ts | 14 +- .../src/telemetry/analytics/analytics.web.ts | 87 +- .../src/telemetry/analytics/constants.ts | 2 + .../src/telemetry/analytics/logging.ts | 17 +- .../trace/AnalyticsNavigationContext.tsx | 2 +- .../utilities/src/telemetry/trace/Trace.tsx | 132 +- .../src/telemetry/trace/TraceContext.tsx | 1 + .../utilities/src/telemetry/trace/utils.ts | 6 +- packages/utilities/tsconfig.json | 3 +- packages/wallet/package.json | 1 - .../CurrencyLogo/CurrencyLogo.test.tsx | 51 + .../CurrencyLogo/LogoWithTxStatus.test.tsx | 315 +++ .../CurrencyLogo/LogoWithTxStatus.tsx | 19 +- .../CurrencyLogo/NetworkLogo.test.tsx | 51 + .../components/CurrencyLogo/NetworkLogo.tsx | 4 +- .../CurrencyLogo/SplitLogo.test.tsx | 120 + .../src/components/CurrencyLogo/SplitLogo.tsx | 2 + .../CurrencyLogo/TokenLogo.test.tsx | 127 + .../src/components/CurrencyLogo/TokenLogo.tsx | 10 +- .../__snapshots__/CurrencyLogo.test.tsx.snap | 125 + .../LogoWithTxStatus.test.tsx.snap | 345 +++ .../__snapshots__/NetworkLogo.test.tsx.snap | 74 + .../__snapshots__/SplitLogo.test.tsx.snap | 162 ++ .../__snapshots__/TokenLogo.test.tsx.snap | 88 + .../__snapshots__/index.test.tsx.snap | 4 + .../WalletConnect/DappIconPlaceholder.tsx | 1 + .../src/components/gating/GatingOverrides.tsx | 50 +- .../modals/BottomSheetModal.web.tsx | 11 +- .../src/components/network/NetworkFee.tsx | 13 +- .../src/components/network/NetworkFilter.tsx | 40 +- .../__snapshots__/NetworkFee.test.tsx.snap | 101 +- packages/wallet/src/constants/chains.ts | 47 +- packages/wallet/src/constants/misc.ts | 3 +- .../src/features/activity/useActivityData.tsx | 2 +- .../wallet/src/features/chains/utils.test.ts | 37 + packages/wallet/src/features/chains/utils.ts | 6 + .../wallet/src/features/dataApi/balances.ts | 6 +- packages/wallet/src/features/dataApi/utils.ts | 24 +- packages/wallet/src/features/gas/types.ts | 8 - .../wallet/src/features/images/ImageUri.tsx | 1 + .../src/features/images/RemoteImage.tsx | 5 +- packages/wallet/src/features/nfts/types.ts | 6 +- packages/wallet/src/features/nfts/utils.ts | 1 + .../components/NetworkChangedNotification.tsx | 3 +- .../NotSupportedNetworkNotification.test.tsx | 15 + .../NotSupportedNetworkNotification.tsx | 21 + ...SupportedNetworkNotification.test.tsx.snap | 225 ++ .../src/features/notifications/types.ts | 6 + .../features/onboarding/OnboardingContext.tsx | 318 +++ .../onboarding/createImportedAccounts.ts | 29 + .../onboarding/createOnboardingAccount.ts | 62 + .../transactions/contexts/SwapTxContext.tsx | 38 - .../hooks/useSwapWarnings.test.ts | 2 +- .../transactions/hooks/useSwapWarnings.tsx | 2 +- .../transactions/refetchGQLQueriesSaga.ts | 2 +- .../transactions/swap/CurrencyInputPanel.tsx | 126 +- .../transactions/swap/SwapDetails.tsx | 3 +- .../features/transactions/swap/SwapFlow.tsx | 57 +- .../transactions/swap/SwapFormButton.tsx | 9 +- .../transactions/swap/SwapFormScreen.tsx | 102 +- .../features/transactions/swap/analytics.ts | 53 +- .../swap/hooks/useExactOutputWillFail.test.ts | 92 + .../swap/hooks/useExactOutputWillFail.ts | 37 + .../swap/hooks/useMostRecentSwapTx.ts | 14 + .../swap/trade/hooks/useDerivedSwapInfo.ts | 19 +- .../swap/trade/hooks/useSetTradeSlippage.ts | 76 +- .../hooks/useShowSwapNetworkNotification.ts | 26 + .../swap/trade/hooks/useSwapCallback.ts | 10 +- .../swap/trade/hooks/useUSDCPrice.ts | 4 +- .../trade/hooks/useWrapTransactionRequest.ts | 59 + .../transactions/swap/trade/legacy/api.ts | 246 -- .../transactions/swap/trade/legacy/hooks.ts | 533 ---- .../swap/trade/legacy/hooks/useRouterQuote.ts | 113 - .../legacy/hooks/useSimulatedGasLimit.ts | 53 - .../swap/trade/legacy/hooks/useTrade.ts | 96 - .../swap/trade/legacy/routeUtils.test.ts | 406 --- .../swap/trade/legacy/routeUtils.ts | 237 -- .../transactions/swap/trade/legacy/types.ts | 124 - .../hooks/useSwapTxAndGasInfoTradingApi.ts | 10 +- .../tradingApi/hooks/useTradingApiTrade.ts | 15 +- .../hooks/useTransactionRequestInfo.ts | 42 +- .../swap/trade/tradingApi/utils.ts | 30 +- .../features/transactions/swap/trade/types.ts | 15 +- .../src/features/transactions/swap/types.ts | 4 +- .../transactions/swap/usePermit2Signature.ts | 1 + .../src/features/transactions/swap/utils.ts | 33 +- .../transactions/transactionWatcherSaga.ts | 2 - .../transfer/TransferTokenForm.tsx | 3 + .../hooks/useShowSendNetworkNotification.ts | 29 + .../wallet/src/features/transactions/types.ts | 2 - packages/wallet/src/features/unitags/hooks.ts | 13 +- .../src/features/wallet/Keyring/Keyring.ts | 2 +- .../wallet/create/createAccountsSaga.test.ts | 189 ++ .../wallet/create/createAccountsSaga.ts | 33 + .../src/features/wallet/getAccountId.ts | 5 + packages/wallet/src/features/wallet/hooks.ts | 26 +- .../wallet/import/importAccountSaga.test.ts | 1 - .../wallet/import/importAccountSaga.ts | 1 - packages/wallet/src/state/README.md | 20 + .../wallet/src/state}/createMigrate.ts | 2 +- packages/wallet/src/state/sharedMigrations.ts | 10 + packages/wallet/src/state/testUtils.ts | 28 + .../wallet/src/test/fixtures/constants.ts | 2 +- .../src/test/fixtures/gql/assets/tokens.ts | 4 + .../src/test/fixtures/wallet/accounts.ts | 6 + .../src/test/fixtures/wallet/currencies.ts | 6 + scripts/ensure-i18n-alphabetized.js | 53 + yarn.lock | 6 +- 784 files changed, 18561 insertions(+), 11972 deletions(-) delete mode 100644 apps/web/src/analytics/index.tsx create mode 100644 apps/web/src/components/NavBar/MobileAppPromoBanner.tsx create mode 100644 apps/web/src/components/Tokens/TokenTable/icons.tsx create mode 100644 apps/web/src/hooks/useAccount.ts create mode 100644 apps/web/src/i18n/LanguageProvider.tsx create mode 100644 apps/web/src/i18n/Plural.tsx create mode 100644 apps/web/src/i18n/Trans.tsx create mode 100644 apps/web/src/i18n/dynamicActivate.tsx create mode 100644 apps/web/src/i18n/initialLocale.ts create mode 100644 apps/web/src/i18n/useTranslation.tsx create mode 100644 packages/ui/src/assets/logos/png/zora-logo.png create mode 100644 packages/uniswap/src/features/telemetry/constants/interface.ts create mode 100644 packages/uniswap/src/types/limits.ts delete mode 100644 packages/uniswap/src/types/quote.ts create mode 100644 packages/uniswap/src/types/screens/interface.ts create mode 100644 packages/uniswap/src/types/wrap.ts create mode 100644 packages/wallet/src/components/CurrencyLogo/CurrencyLogo.test.tsx create mode 100644 packages/wallet/src/components/CurrencyLogo/LogoWithTxStatus.test.tsx create mode 100644 packages/wallet/src/components/CurrencyLogo/NetworkLogo.test.tsx create mode 100644 packages/wallet/src/components/CurrencyLogo/SplitLogo.test.tsx create mode 100644 packages/wallet/src/components/CurrencyLogo/TokenLogo.test.tsx create mode 100644 packages/wallet/src/components/CurrencyLogo/__snapshots__/CurrencyLogo.test.tsx.snap create mode 100644 packages/wallet/src/components/CurrencyLogo/__snapshots__/LogoWithTxStatus.test.tsx.snap create mode 100644 packages/wallet/src/components/CurrencyLogo/__snapshots__/NetworkLogo.test.tsx.snap create mode 100644 packages/wallet/src/components/CurrencyLogo/__snapshots__/SplitLogo.test.tsx.snap create mode 100644 packages/wallet/src/components/CurrencyLogo/__snapshots__/TokenLogo.test.tsx.snap create mode 100644 packages/wallet/src/features/notifications/components/NotSupportedNetworkNotification.test.tsx create mode 100644 packages/wallet/src/features/notifications/components/NotSupportedNetworkNotification.tsx create mode 100644 packages/wallet/src/features/notifications/components/__snapshots__/NotSupportedNetworkNotification.test.tsx.snap create mode 100644 packages/wallet/src/features/onboarding/OnboardingContext.tsx create mode 100644 packages/wallet/src/features/onboarding/createImportedAccounts.ts create mode 100644 packages/wallet/src/features/onboarding/createOnboardingAccount.ts create mode 100644 packages/wallet/src/features/transactions/swap/hooks/useExactOutputWillFail.test.ts create mode 100644 packages/wallet/src/features/transactions/swap/hooks/useExactOutputWillFail.ts create mode 100644 packages/wallet/src/features/transactions/swap/hooks/useMostRecentSwapTx.ts create mode 100644 packages/wallet/src/features/transactions/swap/trade/hooks/useShowSwapNetworkNotification.ts create mode 100644 packages/wallet/src/features/transactions/swap/trade/hooks/useWrapTransactionRequest.ts delete mode 100644 packages/wallet/src/features/transactions/swap/trade/legacy/api.ts delete mode 100644 packages/wallet/src/features/transactions/swap/trade/legacy/hooks.ts delete mode 100644 packages/wallet/src/features/transactions/swap/trade/legacy/hooks/useRouterQuote.ts delete mode 100644 packages/wallet/src/features/transactions/swap/trade/legacy/hooks/useSimulatedGasLimit.ts delete mode 100644 packages/wallet/src/features/transactions/swap/trade/legacy/hooks/useTrade.ts delete mode 100644 packages/wallet/src/features/transactions/swap/trade/legacy/routeUtils.test.ts delete mode 100644 packages/wallet/src/features/transactions/swap/trade/legacy/routeUtils.ts delete mode 100644 packages/wallet/src/features/transactions/swap/trade/legacy/types.ts create mode 100644 packages/wallet/src/features/transactions/transfer/hooks/useShowSendNetworkNotification.ts create mode 100644 packages/wallet/src/features/wallet/create/createAccountsSaga.test.ts create mode 100644 packages/wallet/src/features/wallet/create/createAccountsSaga.ts create mode 100644 packages/wallet/src/features/wallet/getAccountId.ts create mode 100644 packages/wallet/src/state/README.md rename {apps/mobile/src/app => packages/wallet/src/state}/createMigrate.ts (98%) create mode 100644 packages/wallet/src/state/sharedMigrations.ts create mode 100644 packages/wallet/src/state/testUtils.ts create mode 100644 scripts/ensure-i18n-alphabetized.js diff --git a/RELEASE b/RELEASE index d1c31685740..0a35c4fd6d0 100644 --- a/RELEASE +++ b/RELEASE @@ -1,6 +1,6 @@ IPFS hash of the deployment: -- CIDv0: `QmTyp6ePbkJCs819zgUB4Pye4E2cTudcy4SZd5MJkk89Pb` -- CIDv1: `bafybeictz6ffben6zjcs6sk752jegq56ceo7m5nciosofntokzsthxrzey` +- CIDv0: `QmWe2TF9c45GQYs4stbUXrYQvX34xQaaNTdU3T24DiRwLe` +- CIDv1: `bafybeid3kd2hknxwdz7hcsqrebostgihtwucjlonlzw6oaaxjlsbgmcqdm` The latest release is always mirrored at [app.uniswap.org](https://app.uniswap.org). @@ -10,15 +10,55 @@ You can also access the Uniswap Interface from an IPFS gateway. Your Uniswap settings are never remembered across different URLs. IPFS gateways: -- https://bafybeictz6ffben6zjcs6sk752jegq56ceo7m5nciosofntokzsthxrzey.ipfs.dweb.link/ -- https://bafybeictz6ffben6zjcs6sk752jegq56ceo7m5nciosofntokzsthxrzey.ipfs.cf-ipfs.com/ -- [ipfs://QmTyp6ePbkJCs819zgUB4Pye4E2cTudcy4SZd5MJkk89Pb/](ipfs://QmTyp6ePbkJCs819zgUB4Pye4E2cTudcy4SZd5MJkk89Pb/) +- https://bafybeid3kd2hknxwdz7hcsqrebostgihtwucjlonlzw6oaaxjlsbgmcqdm.ipfs.dweb.link/ +- https://bafybeid3kd2hknxwdz7hcsqrebostgihtwucjlonlzw6oaaxjlsbgmcqdm.ipfs.cf-ipfs.com/ +- [ipfs://QmWe2TF9c45GQYs4stbUXrYQvX34xQaaNTdU3T24DiRwLe/](ipfs://QmWe2TF9c45GQYs4stbUXrYQvX34xQaaNTdU3T24DiRwLe/) -### 5.29.1 (2024-05-24) +## 5.30.0 (2024-05-30) + + +### Features + +* **web:** [multichain] handle default input token logic (#8209) 3eed0e3 +* **web:** 4131 default to token project name instead of token name (#8325) 1debde2 +* **web:** 4171 fix duplicate keys in currency search, show balance (#8320) 4c81e41 +* **web:** add Mobile App Promo Banner component (#8257) c03744d +* **web:** Add Multichain Explore Feature Flag and Dropdown option (#8314) 27683d8 +* **web:** converge to single analytics implementation (#8161) 30558ba +* **web:** convert all Trace elements to shared API (#8159) b340e9b +* **web:** convert all TraceEvent usage to shared trace (#8053) 3631853 +* **web:** disable Liquidity Charts on V2 PDP (#8468) 66aad34 +* **web:** migrates to using shared analytics send + typing relevant events (#8051) 11c6325 +* **web:** Sitemap generation round 3?? (#8323) b6e42b6 +* **web:** unicon v2 education label (#8339) f92cd5e +* **web:** use app-specific download links for competitor wallets (#8258) 399844e +* **web:** use new chains with wagmi (#8083) dc14772 +* **web:** use new error dialog design (#6974) ae3628c +* **web:** use Xv2 arbitrum experiment parameters for quote (#8251) 08ab621 ### Bug Fixes -* **web:** Check if WC getNamespaceChainsIds is empty rather than unde… (#8455) 40a9355 +* **web:** add liquidity title fix (#8298) b587de4 +* **web:** Check if WC getNamespaceChainsIds is empty rather than undefined (#8422) 2c76bff +* **web:** dont fetch portfolio balances if multichain ux is not enabled (#8478) 35debe1 +* **web:** e2e test amplitude checks (#8391) ef3a9e5 +* **web:** enable base eth and usdc for moonpay (#8330) ac0ba90 +* **web:** failing e2e tests and wrong ethereum name (#8373) 1cd24a6 +* **web:** filtering out spam on send (#8386) 322551b +* **web:** Fix blocking Testlio bugs - staging (#8592) 55a9345 +* **web:** fix broken translations (#8580) df6f23d +* **web:** fix failing e2e tests (#8480) 1535f19 +* **web:** handle chainName passed as the tab param (#8317) 4555cfd +* **web:** lowercase unicon flag (#8380) dbfe14a +* **web:** mouseover position bug (#8384) 2d8cd91 +* **web:** prevent 1H time period on PDP price chart (#8315) ddc10ca +* **web:** prevent connection from hanging when iframed (#8379) 2feccc4 +* **web:** Unicon loading state (#8415) 76f29f5 + + +### Continuous Integration + +* **web:** update sitemaps b837434 diff --git a/VERSION b/VERSION index 84c9c09c0cb..6f103cc9045 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -web/5.29.1 \ No newline at end of file +web/5.30.0 \ No newline at end of file diff --git a/apps/mobile/.depcheckrc b/apps/mobile/.depcheckrc index 60522dc0673..670b8ef5f8f 100644 --- a/apps/mobile/.depcheckrc +++ b/apps/mobile/.depcheckrc @@ -15,6 +15,7 @@ ignores: [ "@react-native-masked-view/masked-view", "@react-native-firebase/app-check", "react-native-image-colors", + "react-native-restart", # Dependencies that depcheck thinks are missing but are actually present or never used ## Internal packages / workspaces "e2e", diff --git a/apps/mobile/README.md b/apps/mobile/README.md index ffab6f26402..85e0f12e7dd 100644 --- a/apps/mobile/README.md +++ b/apps/mobile/README.md @@ -176,18 +176,7 @@ These are some tools you might want to familiarize yourself with to understand t ## Migrations -We use `redux-persist` to persist Redux state between user sessions. When the Redux state schema is altered, a migration may be needed to transfer the existing persisted state to the new Redux schema. Failing to define a migration results in the app defaulting to the persisted schema, which will very likely cause `undefined` errors because the code has references to Redux state properties that were dropped in favor the persisted schema. - -### When to define a migration - -Anytime a required property is added or any property is renamed or deleted to/from Redux state. Migrations are not necessary when optional properties are added to an existing slice. Make sure to always add new required properties to the `schema.ts` file as well. - -### How to migrate - -1. Increment the `version` of `persistConfig` defined within `store.ts` -2. Create a migration function within `migrations.ts`. The migration key should be the same as the `version` defined in the previous step -3. Write a test for your migration within `migrations.test.ts` -4. Create a new schema within `schema.ts` and ensure it is being exported by the `getSchema` function at the bottom of the file +We use `redux-persist` to persist the Redux state between user sessions. Most of this state is shared between the mobile app and the extension. Please review the [Wallet Migrations README](../../packages/wallet/src/state//README.md) for details on how to write migrations when you add or remove anything from the Redux state structure. ## Troubleshooting @@ -199,6 +188,9 @@ This means whichever package you're trying to run (`[package name]`) wasn’t co - `unable to open file (in target "OneSignalNotificationServiceExtension" in project "Uniswap")`. Resolve this issue by navigating to the `ios/` directory and running `pod update`. +- `Build target hermes-engine: Command PhaseScriptExecution failed with a nonzero exit code` +Node isn't being located correctly during the build phase. Run `which node` and copy the resulting path into `.xcode.env.local`. More context [here](https://github.com/facebook/react-native/issues/42221). + ### Common fixes If something isn’t working the way it should or you’re getting a weird error when trying to run the app, try the following: diff --git a/apps/mobile/android/app/src/main/java/com/uniswap/RnEthersRs.kt b/apps/mobile/android/app/src/main/java/com/uniswap/RnEthersRs.kt index 5b010eb8047..0f1e87a08f8 100644 --- a/apps/mobile/android/app/src/main/java/com/uniswap/RnEthersRs.kt +++ b/apps/mobile/android/app/src/main/java/com/uniswap/RnEthersRs.kt @@ -29,9 +29,12 @@ class RnEthersRs(applicationContext: Context) { } val mnemonicIds: List - get() = keychain.all.keys.map { - key -> key.replace(ENTIRE_MNEMONIC_PREFIX, "") - } + get() = keychain.all.keys.filter { + // MOB-3453 this will need to be updated after fixing prefixes + it.startsWith(MNEMONIC_PREFIX) + }.map { + key -> key.replace(MNEMONIC_PREFIX, "") + } /** * Imports a mnemonic and returns the associated address. @@ -187,6 +190,7 @@ class RnEthersRs(applicationContext: Context) { private const val PREFIX = "com.uniswap" private const val MNEMONIC_PREFIX = ".mnemonic." private const val PRIVATE_KEY_PREFIX = ".privateKey." + // MOB-3453 Android is currently not storing keys with PREFIX private const val ENTIRE_MNEMONIC_PREFIX = PREFIX + MNEMONIC_PREFIX } } diff --git a/apps/mobile/android/app/src/main/java/com/uniswap/onboarding/import/SeedPhraseInputViewModel.kt b/apps/mobile/android/app/src/main/java/com/uniswap/onboarding/import/SeedPhraseInputViewModel.kt index 92e6742d33d..55771b8bb34 100644 --- a/apps/mobile/android/app/src/main/java/com/uniswap/onboarding/import/SeedPhraseInputViewModel.kt +++ b/apps/mobile/android/app/src/main/java/com/uniswap/onboarding/import/SeedPhraseInputViewModel.kt @@ -109,6 +109,10 @@ class SeedPhraseInputViewModel( // TODO gary add production logging and update rust code to convert to Java exceptions Log.d("SeedPhraseInputViewModel", "Storing mnemonic caused error ${e.message}") } + + if (status is Status.Error) { + onInputValidated(false) + } } private fun submitMnemonic(mnemonic: String) { diff --git a/apps/mobile/ios/Uniswap.xcodeproj/project.pbxproj b/apps/mobile/ios/Uniswap.xcodeproj/project.pbxproj index 8c08243e679..2d297719035 100644 --- a/apps/mobile/ios/Uniswap.xcodeproj/project.pbxproj +++ b/apps/mobile/ios/Uniswap.xcodeproj/project.pbxproj @@ -139,7 +139,6 @@ 2F50877AC4F0BB2556A74B60 /* libPods-Uniswap-UniswapTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 89A1B8962666C68EE8B75C18 /* libPods-Uniswap-UniswapTests.a */; }; 5EFB78362B1E585000E77EAC /* ConvertQuery.graphql.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EFB78352B1E585000E77EAC /* ConvertQuery.graphql.swift */; }; 5FF6D300AEE2EB390A272D0E /* libPods-WidgetIntentExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 71A42CE7FF1299C666E6FC79 /* libPods-WidgetIntentExtension.a */; }; - 681301B12A3726EE00A5BF43 /* onboarding_dark.riv in Resources */ = {isa = PBXBuildFile; fileRef = 681301AD2A3726EE00A5BF43 /* onboarding_dark.riv */; }; 681301B22A3726EE00A5BF43 /* pending_send.riv in Resources */ = {isa = PBXBuildFile; fileRef = 681301AE2A3726EE00A5BF43 /* pending_send.riv */; }; 681301B42A3726EE00A5BF43 /* pending_swap.riv in Resources */ = {isa = PBXBuildFile; fileRef = 681301B02A3726EE00A5BF43 /* pending_swap.riv */; }; 6BC7D07E2B5FF02400617C95 /* ScantasticEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC7D07B2B5FF02400617C95 /* ScantasticEncryption.m */; }; @@ -187,6 +186,7 @@ 9FEC9B8B2A858CF1003CD019 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9FEC9B8A2A858CF1003CD019 /* AppDelegate.m */; }; A32F9FBD272343C9002CFCDB /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = A32F9FBC272343C8002CFCDB /* GoogleService-Info.plist */; }; A3F0A5B1272B1DFA00895B25 /* KeychainSwiftDistrib.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F0A5B0272B1DFA00895B25 /* KeychainSwiftDistrib.swift */; }; + A7B8EFCB2BF68F0D00CA4A1C /* FeeData.graphql.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7B8EFCA2BF68F0D00CA4A1C /* FeeData.graphql.swift */; }; AC0EE0982BD826E700BCCF07 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = AC0EE0972BD826E700BCCF07 /* PrivacyInfo.xcprivacy */; }; AEE498F72A85AD86000DDF8E /* Basel-Book.ttf in Resources */ = {isa = PBXBuildFile; fileRef = AEE498F52A85AD86000DDF8E /* Basel-Book.ttf */; }; AEE498F82A85AD86000DDF8E /* Basel-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = AEE498F62A85AD86000DDF8E /* Basel-Medium.ttf */; }; @@ -442,7 +442,6 @@ 56FE9C9AF785221B7E3F4C04 /* Pods-Uniswap.dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Uniswap.dev.xcconfig"; path = "Target Support Files/Pods-Uniswap/Pods-Uniswap.dev.xcconfig"; sourceTree = ""; }; 5EFB78352B1E585000E77EAC /* ConvertQuery.graphql.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvertQuery.graphql.swift; sourceTree = ""; }; 62CEA9F2D5176D20A6402A3E /* Pods-Uniswap.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Uniswap.beta.xcconfig"; path = "Target Support Files/Pods-Uniswap/Pods-Uniswap.beta.xcconfig"; sourceTree = ""; }; - 681301AD2A3726EE00A5BF43 /* onboarding_dark.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = onboarding_dark.riv; sourceTree = ""; }; 681301AE2A3726EE00A5BF43 /* pending_send.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = pending_send.riv; sourceTree = ""; }; 681301B02A3726EE00A5BF43 /* pending_swap.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = pending_swap.riv; sourceTree = ""; }; 6BC7D07B2B5FF02400617C95 /* ScantasticEncryption.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScantasticEncryption.m; sourceTree = ""; }; @@ -495,6 +494,7 @@ 9FEC9B8A2A858CF1003CD019 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Uniswap/AppDelegate.m; sourceTree = ""; }; A32F9FBC272343C8002CFCDB /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; A3F0A5B0272B1DFA00895B25 /* KeychainSwiftDistrib.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainSwiftDistrib.swift; sourceTree = ""; }; + A7B8EFCA2BF68F0D00CA4A1C /* FeeData.graphql.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeeData.graphql.swift; path = MobileSchema/Schema/Objects/FeeData.graphql.swift; sourceTree = ""; }; A7C9F415D0E128A43003E071 /* Pods-Uniswap.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Uniswap.debug.xcconfig"; path = "Target Support Files/Pods-Uniswap/Pods-Uniswap.debug.xcconfig"; sourceTree = ""; }; AC0EE0972BD826E700BCCF07 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = Uniswap/PrivacyInfo.xcprivacy; sourceTree = ""; }; AEE498F52A85AD86000DDF8E /* Basel-Book.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Basel-Book.ttf"; path = "../src/assets/fonts/Basel-Book.ttf"; sourceTree = ""; }; @@ -634,6 +634,7 @@ 072E23872A44D5BD006AD6C9 /* WidgetsCore */ = { isa = PBXGroup; children = ( + A7B8EFCA2BF68F0D00CA4A1C /* FeeData.graphql.swift */, 07F0C28E2A5F3E2E00D5353E /* Env.swift */, 073C67F42A5C8FBE00F6DAD8 /* MobileSchema */, 072E23882A44D5BD006AD6C9 /* WidgetsCore.h */, @@ -1840,6 +1841,7 @@ 0743223B2A83E3CA00F8518D /* NftAssetsFilterInput.graphql.swift in Sources */, 0DC6ADF02B1E2C100092909C /* PortfolioValueModifier.graphql.swift in Sources */, 074322282A83E3CA00F8518D /* TokenProjectMarket.graphql.swift in Sources */, + A7B8EFCB2BF68F0D00CA4A1C /* FeeData.graphql.swift in Sources */, 0743220F2A83E3CA00F8518D /* NftApproveForAll.graphql.swift in Sources */, 0743223C2A83E3CA00F8518D /* SchemaMetadata.graphql.swift in Sources */, 074321FA2A83E3CA00F8518D /* PortfolioBalancesQuery.graphql.swift in Sources */, @@ -2953,7 +2955,8 @@ OTHER_CPLUSPLUSFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "$(inherited)", - " ", + "-Wl", + "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../node_modules/react-native"; SDKROOT = iphoneos; @@ -3019,7 +3022,8 @@ OTHER_CPLUSPLUSFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "$(inherited)", - " ", + "-Wl", + "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../node_modules/react-native"; SDKROOT = iphoneos; @@ -3172,7 +3176,8 @@ OTHER_CPLUSPLUSFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "$(inherited)", - " ", + "-Wl", + "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../node_modules/react-native"; SDKROOT = iphoneos; @@ -3346,7 +3351,8 @@ OTHER_CPLUSPLUSFLAGS = "$(inherited)"; OTHER_LDFLAGS = ( "$(inherited)", - " ", + "-Wl", + "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../node_modules/react-native"; SDKROOT = iphoneos; diff --git a/apps/mobile/jest-setup.js b/apps/mobile/jest-setup.js index f924f5a6224..6e9c2fd5bc0 100644 --- a/apps/mobile/jest-setup.js +++ b/apps/mobile/jest-setup.js @@ -9,17 +9,6 @@ import { localizeMock as mockRNLocalize } from 'react-native-localize/mock' import { AppearanceSettingType } from 'wallet/src/features/appearance/slice' import { mockLocalizationContext } from 'wallet/src/test/mocks/utils' -// avoids polluting console in test runs, while keeping important log levels -global.console = { - ...console, - // uncomment to ignore a specific log level - log: jest.fn(), - debug: jest.fn(), - info: jest.fn(), - // warn: jest.fn(), - // error: jest.fn(), -} - // Mock Sentry crash reporting jest.mock('@sentry/react-native', () => ({ init: () => jest.fn(), diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 1d512e58c1f..1bcde948c1b 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -131,6 +131,7 @@ "react-native-pager-view": "6.0.1", "react-native-permissions": "3.6.0", "react-native-reanimated": "3.8.1", + "react-native-restart": "0.0.27", "react-native-safe-area-context": "4.9.0", "react-native-screens": "3.30.1", "react-native-splash-screen": "3.3.0", diff --git a/apps/mobile/src/app/App.tsx b/apps/mobile/src/app/App.tsx index 5d61879605a..9db7d5be874 100644 --- a/apps/mobile/src/app/App.tsx +++ b/apps/mobile/src/app/App.tsx @@ -46,7 +46,7 @@ import { flexStyles, useIsDarkMode } from 'ui/src' import { config } from 'uniswap/src/config' import { uniswapUrls } from 'uniswap/src/constants/urls' import { DUMMY_STATSIG_SDK_KEY } from 'uniswap/src/features/gating/constants' -import { WALLET_EXPERIMENTS } from 'uniswap/src/features/gating/experiments' +import { Experiments } from 'uniswap/src/features/gating/experiments' import { WALLET_FEATURE_FLAG_NAMES } from 'uniswap/src/features/gating/flags' import { loadStatsigOverrides } from 'uniswap/src/features/gating/overrides/customPersistedOverrides' import { Statsig, StatsigProvider } from 'uniswap/src/features/gating/sdk/statsig' @@ -177,10 +177,10 @@ function SentryTags({ children }: PropsWithChildren): JSX.Element { Sentry.setTag(`featureFlag.${flagKey}`, Statsig.checkGateWithExposureLoggingDisabled(flagKey)) } - for (const [_, experimentDef] of WALLET_EXPERIMENTS.entries()) { + for (const experiment of Object.values(Experiments)) { Sentry.setTag( - `experiment.${experimentDef.name}`, - Statsig.getExperimentWithExposureLoggingDisabled(experimentDef.name).getGroupName() + `experiment.${experiment}`, + Statsig.getExperimentWithExposureLoggingDisabled(experiment).getGroupName() ) } }, []) diff --git a/apps/mobile/src/app/migrations.test.ts b/apps/mobile/src/app/migrations.test.ts index 1d5eb637219..9a8ad981767 100644 --- a/apps/mobile/src/app/migrations.test.ts +++ b/apps/mobile/src/app/migrations.test.ts @@ -1,7 +1,6 @@ /* eslint-disable max-lines */ import { BigNumber } from 'ethers' import mockdate from 'mockdate' -import createMigrate from 'src/app/createMigrate' import { migrations, OLD_DEMO_ACCOUNT_ADDRESS } from 'src/app/migrations' import { getSchema, @@ -104,6 +103,8 @@ import { SignerMnemonicAccount, } from 'wallet/src/features/wallet/accounts/types' import { initialWalletState, SwapProtectionSetting } from 'wallet/src/features/wallet/slice' +import { createMigrate } from 'wallet/src/state/createMigrate' +import { getAllKeysOfNestedObject } from 'wallet/src/state/testUtils' import { fiatPurchaseTransactionInfo, signerMnemonicAccount, @@ -124,26 +125,6 @@ const fiatOnRampTxDetailsFailed = transactionDetails({ }), }) -// helps with object assignment -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const getAllKeysOfNestedObject = (obj: any, prefix = ''): string[] => { - const keys = Object.keys(obj) - if (!keys.length && prefix !== '') { - return [prefix.slice(0, -1)] - } - return keys.reduce((res, el) => { - if (Array.isArray(obj[el])) { - return [...res] - } - - if (typeof obj[el] === 'object' && obj[el] !== null) { - return [...res, ...getAllKeysOfNestedObject(obj[el], prefix + el + '.')] - } - - return [...res, prefix + el] - }, []) -} - describe('Redux state migrations', () => { it('is able to perform all migrations starting from the initial schema', async () => { const initialSchemaStub = { @@ -204,6 +185,10 @@ describe('Redux state migrations', () => { }, } + if (!migratedSchema) { + throw new Error('Migrated schema is undefined') + } + const migratedSchemaKeys = new Set(getAllKeysOfNestedObject(migratedSchema)) const latestSchemaKeys = new Set(getAllKeysOfNestedObject(getSchema())) const initialStateKeys = new Set(getAllKeysOfNestedObject(initialState)) diff --git a/apps/mobile/src/app/migrations.ts b/apps/mobile/src/app/migrations.ts index 1d280a9cecc..263617d7d5e 100644 --- a/apps/mobile/src/app/migrations.ts +++ b/apps/mobile/src/app/migrations.ts @@ -19,6 +19,7 @@ import { } from 'wallet/src/features/transactions/types' import { Account, AccountType } from 'wallet/src/features/wallet/accounts/types' import { SwapProtectionSetting } from 'wallet/src/features/wallet/slice' +import { removeWalletIsUnlockedState } from 'wallet/src/state/sharedMigrations' export const OLD_DEMO_ACCOUNT_ADDRESS = '0xdd0E380579dF30E38524F9477808d9eE37E2dEa6' @@ -876,10 +877,7 @@ export const migrations = { return newState }, - 63: function removeWalletIsUnlockedState(state: any) { - const newState = { ...state } - delete newState.wallet.isUnlocked - - return newState - }, + 63: removeWalletIsUnlockedState, } + +export const MOBILE_STATE_VERSION = 63 diff --git a/apps/mobile/src/app/modals/AccountSwitcherModal.tsx b/apps/mobile/src/app/modals/AccountSwitcherModal.tsx index 8f015effbc8..d98f1f9cb43 100644 --- a/apps/mobile/src/app/modals/AccountSwitcherModal.tsx +++ b/apps/mobile/src/app/modals/AccountSwitcherModal.tsx @@ -8,8 +8,6 @@ import { AccountList } from 'src/components/accounts/AccountList' import { isCloudStorageAvailable } from 'src/features/CloudBackup/RNCloudStorageBackupsManager' import { closeModal, openModal } from 'src/features/modals/modalSlice' import { selectModalState } from 'src/features/modals/selectModalState' -import { useCompleteOnboardingCallback } from 'src/features/onboarding/hooks' -import { useSagaStatus } from 'src/utils/useSagaStatus' import { Button, Flex, @@ -21,24 +19,22 @@ import { } from 'ui/src' import { Plus } from 'ui/src/components/icons' import { spacing } from 'ui/src/theme' -import { ElementName, ModalName } from 'uniswap/src/features/telemetry/constants' +import { ElementName, MobileEventName, ModalName } from 'uniswap/src/features/telemetry/constants' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { ImportType, OnboardingEntryPoint } from 'uniswap/src/types/onboarding' import { MobileScreens, OnboardingScreens } from 'uniswap/src/types/screens/mobile' import { isAndroid } from 'uniswap/src/utils/platform' import { AddressDisplay } from 'wallet/src/components/accounts/AddressDisplay' import { ActionSheetModal, MenuItemProp } from 'wallet/src/components/modals/ActionSheetModal' import { BottomSheetModal } from 'wallet/src/components/modals/BottomSheetModal' -import { AccountType } from 'wallet/src/features/wallet/accounts/types' -import { - createAccountActions, - createAccountSagaName, -} from 'wallet/src/features/wallet/create/createAccountSaga' -import { - PendingAccountActions, - pendingAccountActions, -} from 'wallet/src/features/wallet/create/pendingAccountsSaga' +import { createOnboardingAccount } from 'wallet/src/features/onboarding/createOnboardingAccount' +import { AccountType, BackupType } from 'wallet/src/features/wallet/accounts/types' +import { createAccountsActions } from 'wallet/src/features/wallet/create/createAccountsSaga' import { useActiveAccountAddress, useNativeAccountExists } from 'wallet/src/features/wallet/hooks' -import { selectAllAccountsSorted } from 'wallet/src/features/wallet/selectors' +import { + selectAllAccountsSorted, + selectSortedSignerMnemonicAccounts, +} from 'wallet/src/features/wallet/selectors' import { setAccountAsActive } from 'wallet/src/features/wallet/slice' import { openSettings } from 'wallet/src/utils/linking' @@ -74,13 +70,9 @@ export function AccountSwitcher({ onClose }: { onClose: () => void }): JSX.Eleme const dispatch = useAppDispatch() const hasImportedSeedPhrase = useNativeAccountExists() const modalState = useAppSelector(selectModalState(ModalName.AccountSwitcher)) - const onCompleteOnboarding = useCompleteOnboardingCallback({ - entryPoint: OnboardingEntryPoint.Sidebar, - importType: hasImportedSeedPhrase ? ImportType.CreateAdditional : ImportType.CreateNew, - }) + const sortedMnemonicAccounts = useAppSelector(selectSortedSignerMnemonicAccounts) const [showAddWalletModal, setShowAddWalletModal] = useState(false) - const [createdAdditionalAccount, setCreatedAdditionalAccount] = useState(false) const accounts = useAppSelector(selectAllAccountsSorted) @@ -115,22 +107,33 @@ export function AccountSwitcher({ onClose }: { onClose: () => void }): JSX.Eleme }) } - // Pick up account creation and activate - useSagaStatus(createAccountSagaName, async () => { - if (createdAdditionalAccount) { - setCreatedAdditionalAccount(false) - await onCompleteOnboarding() - } - }) - const addWalletOptions = useMemo(() => { - const onPressCreateNewWallet = (): void => { - // Ensure no pending accounts - dispatch(pendingAccountActions.trigger(PendingAccountActions.ActivateOneAndDelete)) - dispatch(createAccountActions.trigger()) + const createAdditionalAccount = async (): Promise => { + // Generate new account + const newAccount = await createOnboardingAccount(sortedMnemonicAccounts) + + // Create new account in redux + dispatch( + createAccountsActions.trigger({ + accounts: [newAccount], + activateFirst: true, + }) + ) + // Log analytics event + sendAnalyticsEvent(MobileEventName.WalletAdded, { + wallet_type: ImportType.CreateAdditional, + accounts_imported_count: 1, + wallets_imported: [newAccount.address], + cloud_backup_used: newAccount.backups?.includes(BackupType.Cloud) ?? false, + }) + } + + const onPressCreateNewWallet = async (): Promise => { + setShowAddWalletModal(false) + onClose() if (hasImportedSeedPhrase) { - setCreatedAdditionalAccount(true) + await createAdditionalAccount() } else { // create pending account and place into welcome flow navigate(MobileScreens.OnboardingStack, { @@ -141,9 +144,6 @@ export function AccountSwitcher({ onClose }: { onClose: () => void }): JSX.Eleme }, }) } - - setShowAddWalletModal(false) - onClose() } const onPressAddViewOnlyWallet = (): void => { @@ -254,7 +254,7 @@ export function AccountSwitcher({ onClose }: { onClose: () => void }): JSX.Eleme } return options - }, [activeAccountAddress, dispatch, hasImportedSeedPhrase, onClose, t]) + }, [activeAccountAddress, dispatch, hasImportedSeedPhrase, onClose, sortedMnemonicAccounts, t]) const accountsWithoutActive = accounts.filter((a) => a.address !== activeAccountAddress) diff --git a/apps/mobile/src/app/navigation/navigation.tsx b/apps/mobile/src/app/navigation/navigation.tsx index e1d83576150..33f943c7b61 100644 --- a/apps/mobile/src/app/navigation/navigation.tsx +++ b/apps/mobile/src/app/navigation/navigation.tsx @@ -72,6 +72,7 @@ import { OnboardingScreens, UnitagScreens, } from 'uniswap/src/types/screens/mobile' +import { OnboardingContextProvider } from 'wallet/src/features/onboarding/OnboardingContext' import { useActiveAccountWithThrow } from 'wallet/src/features/wallet/hooks' import { selectFinishedOnboarding } from 'wallet/src/features/wallet/selectors' @@ -235,87 +236,92 @@ export function OnboardingStackNavigator(): JSX.Element { : SeedPhraseInputScreen return ( - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + ) } diff --git a/apps/mobile/src/app/navigation/types.ts b/apps/mobile/src/app/navigation/types.ts index 4244c9ab6b0..92a6994705d 100644 --- a/apps/mobile/src/app/navigation/types.ts +++ b/apps/mobile/src/app/navigation/types.ts @@ -7,7 +7,6 @@ import { import { NativeStackNavigationProp, NativeStackScreenProps } from '@react-navigation/native-stack' import { EducationContentType } from 'src/components/education' import { HomeScreenTabIndex } from 'src/screens/HomeScreenTabIndex' -import { UnitagClaim } from 'uniswap/src/features/unitags/types' import { ImportType, OnboardingEntryPoint } from 'uniswap/src/types/onboarding' import { FiatOnRampScreens, @@ -70,7 +69,6 @@ export type SettingsStackParamList = { export type OnboardingStackBaseParams = { importType: ImportType entryPoint: OnboardingEntryPoint - unitagClaim?: UnitagClaim } export type UnitagEntryPoint = diff --git a/apps/mobile/src/app/saga.ts b/apps/mobile/src/app/saga.ts index 966ee84328a..efbad64e6ae 100644 --- a/apps/mobile/src/app/saga.ts +++ b/apps/mobile/src/app/saga.ts @@ -36,6 +36,12 @@ import { createAccountSaga, createAccountSagaName, } from 'wallet/src/features/wallet/create/createAccountSaga' +import { + createAccountsActions, + createAccountsReducer, + createAccountsSaga, + createAccountsSagaName, +} from 'wallet/src/features/wallet/create/createAccountsSaga' import { pendingAccountSaga } from 'wallet/src/features/wallet/create/pendingAccountsSaga' import { importAccountActions, @@ -70,6 +76,12 @@ export const monitoredSagas: Record = { reducer: createAccountReducer, actions: createAccountActions, }, + [createAccountsSagaName]: { + name: createAccountsSagaName, + wrappedSaga: createAccountsSaga, + reducer: createAccountsReducer, + actions: createAccountsActions, + }, [editAccountSagaName]: { name: editAccountSagaName, wrappedSaga: editAccountSaga, diff --git a/apps/mobile/src/app/store.ts b/apps/mobile/src/app/store.ts index 12431a0cc90..286d8fbdea4 100644 --- a/apps/mobile/src/app/store.ts +++ b/apps/mobile/src/app/store.ts @@ -3,13 +3,13 @@ import { isRejectedWithValue } from '@reduxjs/toolkit' import * as Sentry from '@sentry/react' import { MMKV } from 'react-native-mmkv' import { Storage, persistReducer, persistStore } from 'redux-persist' -import createMigrate from 'src/app/createMigrate' -import { migrations } from 'src/app/migrations' +import { MOBILE_STATE_VERSION, migrations } from 'src/app/migrations' import { isNonJestDev } from 'utilities/src/environment' import { logger } from 'utilities/src/logger/logger' import { fiatOnRampAggregatorApi, fiatOnRampApi } from 'wallet/src/features/fiatOnRamp/api' import { importAccountSagaName } from 'wallet/src/features/wallet/import/importAccountSaga' import { createStore } from 'wallet/src/state' +import { createMigrate } from 'wallet/src/state/createMigrate' import { RootReducerNames, sharedPersistedStateWhitelist } from 'wallet/src/state/reducer' import { MobileState, ReducerNames, mobileReducer } from './reducer' import { mobileSaga } from './saga' @@ -66,7 +66,7 @@ export const persistConfig = { key: 'root', storage: reduxStorage, whitelist, - version: 63, + version: MOBILE_STATE_VERSION, migrate: createMigrate(migrations), } diff --git a/apps/mobile/src/components/PriceExplorer/constants.ts b/apps/mobile/src/components/PriceExplorer/constants.ts index 1ea7da45fb0..fdcbf0a8f52 100644 --- a/apps/mobile/src/components/PriceExplorer/constants.ts +++ b/apps/mobile/src/components/PriceExplorer/constants.ts @@ -2,8 +2,6 @@ import { HistoryDuration } from 'uniswap/src/data/graphql/uniswap-data-api/__gen import { ElementName } from 'uniswap/src/features/telemetry/constants' import i18n from 'uniswap/src/i18n/i18n' -export const NUM_GRAPHS = 5 - export const BUTTON_PADDING = 20 export const CURSOR_INNER_SIZE = 12 @@ -32,4 +30,7 @@ export const TIME_RANGES = [ i18n.t('token.priceExplorer.timeRangeLabel.year'), ElementName.TimeFrame1Y, ], + [HistoryDuration.Max, i18n.t('token.priceExplorer.timeRangeLabel.all'), ElementName.TimeFrameAll], ] as const + +export const NUM_GRAPHS = TIME_RANGES.length diff --git a/apps/mobile/src/components/TokenDetails/TokenBalances.tsx b/apps/mobile/src/components/TokenDetails/TokenBalances.tsx index cab2d992894..6e17dc1afde 100644 --- a/apps/mobile/src/components/TokenDetails/TokenBalances.tsx +++ b/apps/mobile/src/components/TokenDetails/TokenBalances.tsx @@ -137,7 +137,7 @@ function OtherChainBalance({ const { convertFiatAmountFormatted, formatNumberOrString } = useLocalizationContext() return ( - + navigate(balance.currencyInfo.currencyId)}> diff --git a/apps/mobile/src/components/Trace/TraceUserProperties.test.tsx b/apps/mobile/src/components/Trace/TraceUserProperties.test.tsx index 621a6e6b1ce..cd463d0fe0d 100644 --- a/apps/mobile/src/components/Trace/TraceUserProperties.test.tsx +++ b/apps/mobile/src/components/Trace/TraceUserProperties.test.tsx @@ -8,6 +8,7 @@ import { AuthMethod } from 'src/features/telemetry/utils' import * as versionUtils from 'src/utils/version' import * as useIsDarkModeFile from 'ui/src/hooks/useIsDarkMode' import { MobileUserPropertyName } from 'uniswap/src/features/telemetry/user' +// eslint-disable-next-line no-restricted-imports import { analytics } from 'utilities/src/telemetry/analytics/analytics' import { FiatCurrency } from 'wallet/src/features/fiatCurrency/constants' import * as fiatCurrencyHooks from 'wallet/src/features/fiatCurrency/hooks' @@ -102,35 +103,54 @@ describe('TraceUserProperties', () => { }) // Check setUserProperty calls with correct values - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.AppVersion, '1.0.0.345') - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.DarkMode, true) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.ActiveWalletAddress, 'address') + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.AppVersion, '1.0.0.345', undefined) + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.DarkMode, true, undefined) + expect(mocked).toHaveBeenCalledWith( + MobileUserPropertyName.ActiveWalletAddress, + 'address', + undefined + ) expect(mocked).toHaveBeenCalledWith( MobileUserPropertyName.ActiveWalletType, - AccountType.SignerMnemonic + AccountType.SignerMnemonic, + undefined + ) + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.IsCloudBackedUp, true, undefined) + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.IsPushEnabled, true, undefined) + expect(mocked).toHaveBeenCalledWith( + MobileUserPropertyName.IsHideSmallBalancesEnabled, + false, + undefined + ) + expect(mocked).toHaveBeenCalledWith( + MobileUserPropertyName.IsHideSpamTokensEnabled, + true, + undefined + ) + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.WalletViewOnlyCount, 2, undefined) + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.WalletSignerCount, 3, undefined) + expect(mocked).toHaveBeenCalledWith( + MobileUserPropertyName.WalletSignerAccounts, + [address1, address2, address3], + undefined ) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.IsCloudBackedUp, true) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.IsPushEnabled, true) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.IsHideSmallBalancesEnabled, false) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.IsHideSpamTokensEnabled, true) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.WalletViewOnlyCount, 2) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.WalletSignerCount, 3) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.WalletSignerAccounts, [ - address1, - address2, - address3, - ]) expect(mocked).toHaveBeenCalledWith( MobileUserPropertyName.WalletSwapProtectionSetting, - SwapProtectionSetting.On + SwapProtectionSetting.On, + undefined + ) + expect(mocked).toHaveBeenCalledWith( + MobileUserPropertyName.AppOpenAuthMethod, + AuthMethod.FaceId, + undefined ) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.AppOpenAuthMethod, AuthMethod.FaceId) expect(mocked).toHaveBeenCalledWith( MobileUserPropertyName.TransactionAuthMethod, - AuthMethod.FaceId + AuthMethod.FaceId, + undefined ) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.Language, 'English') - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.Currency, 'USD') + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.Language, 'English', undefined) + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.Currency, 'USD', undefined) expect(mocked).toHaveBeenCalledTimes(17) }) @@ -165,14 +185,19 @@ describe('TraceUserProperties', () => { }) // Check setUserProperty calls with correct values - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.AppVersion, '1.0.0.345') - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.DarkMode, true) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.WalletViewOnlyCount, 0) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.WalletSignerCount, 0) - expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.AppOpenAuthMethod, AuthMethod.None) + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.AppVersion, '1.0.0.345', undefined) + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.DarkMode, true, undefined) + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.WalletViewOnlyCount, 0, undefined) + expect(mocked).toHaveBeenCalledWith(MobileUserPropertyName.WalletSignerCount, 0, undefined) + expect(mocked).toHaveBeenCalledWith( + MobileUserPropertyName.AppOpenAuthMethod, + AuthMethod.None, + undefined + ) expect(mocked).toHaveBeenCalledWith( MobileUserPropertyName.TransactionAuthMethod, - AuthMethod.None + AuthMethod.None, + undefined ) expect(mocked).toHaveBeenCalledTimes(11) diff --git a/apps/mobile/src/components/Trace/TraceUserProperties.tsx b/apps/mobile/src/components/Trace/TraceUserProperties.tsx index 73c2eba8efc..2da371a39a9 100644 --- a/apps/mobile/src/components/Trace/TraceUserProperties.tsx +++ b/apps/mobile/src/components/Trace/TraceUserProperties.tsx @@ -11,6 +11,7 @@ import { getFullAppVersion } from 'src/utils/version' import { useIsDarkMode } from 'ui/src' import { MobileUserPropertyName, setUserProperty } from 'uniswap/src/features/telemetry/user' import { isAndroid } from 'uniswap/src/utils/platform' +// eslint-disable-next-line no-restricted-imports import { analytics } from 'utilities/src/telemetry/analytics/analytics' import { useAppFiatCurrency } from 'wallet/src/features/fiatCurrency/hooks' import { useGatingUserPropertyUsernames } from 'wallet/src/features/gating/userPropertyHooks' diff --git a/apps/mobile/src/components/WalletConnect/RequestModal/WalletConnectRequestModal.tsx b/apps/mobile/src/components/WalletConnect/RequestModal/WalletConnectRequestModal.tsx index 734157e8fd5..4ad51ed26c1 100644 --- a/apps/mobile/src/components/WalletConnect/RequestModal/WalletConnectRequestModal.tsx +++ b/apps/mobile/src/components/WalletConnect/RequestModal/WalletConnectRequestModal.tsx @@ -164,6 +164,7 @@ export function WalletConnectRequestModal({ onClose, request }: Props): JSX.Elem account: signerAccount, dapp: request.dapp, chainId, + request, }) ) } else { diff --git a/apps/mobile/src/components/WalletConnect/ScanSheet/WalletConnectModal.tsx b/apps/mobile/src/components/WalletConnect/ScanSheet/WalletConnectModal.tsx index 9a3485401fd..0b44bd1e8c8 100644 --- a/apps/mobile/src/components/WalletConnect/ScanSheet/WalletConnectModal.tsx +++ b/apps/mobile/src/components/WalletConnect/ScanSheet/WalletConnectModal.tsx @@ -79,7 +79,10 @@ export function WalletConnectModal({ } await HapticFeedback.selection() - const supportedURI = await getSupportedURI(uri, { isUwULinkEnabled, isScantasticEnabled }) + const supportedURI = await getSupportedURI(uri, { + isUwULinkEnabled, + isScantasticEnabled, + }) if (!supportedURI) { setShouldFreezeCamera(true) Alert.alert( @@ -127,7 +130,9 @@ export function WalletConnectModal({ try { await pairWithWalletConnectURI(supportedURI.value) } catch (error) { - logger.error(error, { tags: { file: 'WalletConnectModal', function: 'onScanCode' } }) + logger.error(error, { + tags: { file: 'WalletConnectModal', function: 'onScanCode' }, + }) Alert.alert( t('walletConnect.error.general.title'), t('walletConnect.error.general.message'), @@ -225,7 +230,10 @@ export function WalletConnectModal({ amount: parsedUwulinkRequest.amount, tokenAddress: parsedUwulinkRequest.tokenAddress, isStablecoin: parsedUwulinkRequest.isStablecoin, - transaction: { from: activeAccount.address, ...preparedTransaction }, + transaction: { + from: activeAccount.address, + ...preparedTransaction, + }, }, }) ) @@ -236,15 +244,24 @@ export function WalletConnectModal({ request: { ...newRequest, type: EthMethod.EthSendTransaction, - transaction: { from: activeAccount.address, ...parsedUwulinkRequest.value }, + transaction: { + from: activeAccount.address, + ...parsedUwulinkRequest.value, + }, }, }) ) } onClose() } catch (_) { - setShouldFreezeCamera(false) - Alert.alert(t('walletConnect.error.uwu.title'), t('walletConnect.error.uwu.scan')) + Alert.alert(t('walletConnect.error.uwu.title'), t('walletConnect.error.uwu.scan'), [ + { + text: t('common.button.ok'), + onPress: (): void => { + setShouldFreezeCamera(false) + }, + }, + ]) } } diff --git a/apps/mobile/src/components/WalletConnect/ScanSheet/util.ts b/apps/mobile/src/components/WalletConnect/ScanSheet/util.ts index b859bd3cf2d..b5a57616779 100644 --- a/apps/mobile/src/components/WalletConnect/ScanSheet/util.ts +++ b/apps/mobile/src/components/WalletConnect/ScanSheet/util.ts @@ -196,7 +196,7 @@ export function isAllowedUwuLinkRequest( // generic transactions const { to, value } = request.value const belowMaximumValue = - value && parseFloat(value) <= parseEther(UWULINK_MAX_TXN_VALUE).toNumber() + !value || parseFloat(value) <= parseEther(UWULINK_MAX_TXN_VALUE).toNumber() const isAllowedContractAddress = to && allowlist.contracts.some((item) => areAddressesEqual(item.address, to)) diff --git a/apps/mobile/src/components/explore/__snapshots__/TokenItem.test.tsx.snap b/apps/mobile/src/components/explore/__snapshots__/TokenItem.test.tsx.snap index cbdd331d42e..298e42d40d2 100644 --- a/apps/mobile/src/components/explore/__snapshots__/TokenItem.test.tsx.snap +++ b/apps/mobile/src/components/explore/__snapshots__/TokenItem.test.tsx.snap @@ -97,6 +97,7 @@ exports[`TokenItem renders without error 1`] = ` "width": 40, } } + testID="token-logo" > diff --git a/apps/mobile/src/features/CloudBackup/CloudBackupProcessingAnimation.tsx b/apps/mobile/src/features/CloudBackup/CloudBackupProcessingAnimation.tsx index 2dca6cdc516..05e159a8f02 100644 --- a/apps/mobile/src/features/CloudBackup/CloudBackupProcessingAnimation.tsx +++ b/apps/mobile/src/features/CloudBackup/CloudBackupProcessingAnimation.tsx @@ -3,7 +3,6 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack' import React, { useCallback, useEffect, useReducer } from 'react' import { useTranslation } from 'react-i18next' import { ActivityIndicator, Alert } from 'react-native' -import { useAppDispatch } from 'src/app/hooks' import { OnboardingStackParamList, SettingsStackParamList } from 'src/app/navigation/types' import { backupMnemonicToCloudStorage } from 'src/features/CloudBackup/RNCloudStorageBackupsManager' import { Flex, Text, useSporeColors } from 'ui/src' @@ -14,12 +13,14 @@ import { logger } from 'utilities/src/logger/logger' import { ONE_SECOND_MS } from 'utilities/src/time/time' import { promiseMinDelay } from 'utilities/src/time/timing' import { CheckmarkCircle } from 'wallet/src/components/icons/CheckmarkCircle' +import { useOnboardingContext } from 'wallet/src/features/onboarding/OnboardingContext' import { EditAccountAction, editAccountActions, } from 'wallet/src/features/wallet/accounts/editAccountSaga' import { AccountType, BackupType } from 'wallet/src/features/wallet/accounts/types' -import { useAccount } from 'wallet/src/features/wallet/hooks' +import { useAccountIfExists } from 'wallet/src/features/wallet/hooks' +import { useAppDispatch } from 'wallet/src/state' type Props = { accountAddress: Address @@ -41,9 +42,18 @@ export function CloudBackupProcessingAnimation({ }: Props): JSX.Element { const { t } = useTranslation() const dispatch = useAppDispatch() + const { addBackupMethod, getImportedAccounts, getOnboardingAccount } = useOnboardingContext() + const onboardingAccount = getOnboardingAccount() + const importedAccounts = getImportedAccounts() const colors = useSporeColors() + const activeAccount = useAccountIfExists(accountAddress) + + const account = activeAccount || onboardingAccount || importedAccounts?.[0] + + if (!account) { + throw Error('No account available for backup') + } - const account = useAccount(accountAddress) if (account.type !== AccountType.SignerMnemonic) { throw new Error('Account is not mnemonic account') } @@ -66,14 +76,17 @@ export function CloudBackupProcessingAnimation({ try { // Ensure processing state is shown for at least 1s await promiseMinDelay(backupMnemonicToCloudStorage(mnemonicId, password), ONE_SECOND_MS) - - dispatch( - editAccountActions.trigger({ - type: EditAccountAction.AddBackupMethod, - address: accountAddress, - backupMethod: BackupType.Cloud, - }) - ) + if (activeAccount) { + dispatch( + editAccountActions.trigger({ + type: EditAccountAction.AddBackupMethod, + address: accountAddress, + backupMethod: BackupType.Cloud, + }) + ) + } else { + addBackupMethod(BackupType.Cloud) + } } catch (error) { logger.error(error, { tags: { file: 'CloudBackupProcessingScreen', function: 'onPressNext' }, @@ -93,7 +106,16 @@ export function CloudBackupProcessingAnimation({ ] ) } - }, [accountAddress, dispatch, mnemonicId, onErrorPress, password, t]) + }, [ + accountAddress, + activeAccount, + addBackupMethod, + dispatch, + mnemonicId, + onErrorPress, + password, + t, + ]) /** * Delays cloud backup to avoid android oauth consent screen blocking navigation transition diff --git a/apps/mobile/src/features/firebase/firebaseDataSaga.ts b/apps/mobile/src/features/firebase/firebaseDataSaga.ts index 9bc188160c2..d0795e232c7 100644 --- a/apps/mobile/src/features/firebase/firebaseDataSaga.ts +++ b/apps/mobile/src/features/firebase/firebaseDataSaga.ts @@ -58,17 +58,26 @@ export function* firebaseDataWatcher() { } function* syncNotificationsWithFirebase() { - const accounts = yield* select(selectNonPendingAccounts) - const addresses = Object.keys(accounts) - - for (const address of addresses) { - const notificationsEnabled = yield* select(selectAccountNotificationSetting, address) - - if (notificationsEnabled) { - yield* call(mapFirebaseUidToAddresses, [address]) - } else { - yield* call(deleteFirebaseMetadata, address) - yield* call(disassociateFirebaseUidFromAddresses, [address]) + try { + const accounts = yield* select(selectNonPendingAccounts) + const addresses = Object.keys(accounts) + + for (const address of addresses) { + const notificationsEnabled = yield* select(selectAccountNotificationSetting, address) + + if (notificationsEnabled) { + yield* call(mapFirebaseUidToAddresses, [address]) + } else { + yield* call(deleteFirebaseMetadata, address) + yield* call(disassociateFirebaseUidFromAddresses, [address]) + } + } + } catch (error) { + // Permission denied error is expected for syncing when notifications are disabled + if (!(error instanceof Error && error.message.includes('permission-denied'))) { + logger.error(error, { + tags: { file: 'firebaseDataSaga', function: 'syncNotificationsWithFirebase' }, + }) } } } diff --git a/apps/mobile/src/features/nfts/item/CollectionPreviewCard.tsx b/apps/mobile/src/features/nfts/item/CollectionPreviewCard.tsx index a09cc97657f..f8f9bbffff8 100644 --- a/apps/mobile/src/features/nfts/item/CollectionPreviewCard.tsx +++ b/apps/mobile/src/features/nfts/item/CollectionPreviewCard.tsx @@ -22,12 +22,14 @@ interface CollectionPreviewCardProps { fallbackData?: NFTItem onPress: () => void loading: boolean + shouldDisableLink?: boolean } export function CollectionPreviewCard({ collection, fallbackData, onPress, loading, + shouldDisableLink, }: CollectionPreviewCardProps): JSX.Element { const colors = useSporeColors() const { t } = useTranslation() @@ -36,7 +38,8 @@ export function CollectionPreviewCard({ return } - const isViewableCollection = Boolean(collection || fallbackData?.contractAddress) + const isViewableCollection = + !shouldDisableLink && Boolean(collection || fallbackData?.contractAddress) return ( diff --git a/apps/mobile/src/features/onboarding/hooks.ts b/apps/mobile/src/features/onboarding/hooks.ts index 3356a9a6189..c1807570d1f 100644 --- a/apps/mobile/src/features/onboarding/hooks.ts +++ b/apps/mobile/src/features/onboarding/hooks.ts @@ -1,26 +1,11 @@ import { SharedEventName } from '@uniswap/analytics-events' import { useAppDispatch } from 'src/app/hooks' import { OnboardingStackBaseParams, useOnboardingStackNavigation } from 'src/app/navigation/types' -import { FeatureFlags } from 'uniswap/src/features/gating/flags' -import { useFeatureFlag } from 'uniswap/src/features/gating/hooks' -import { MobileAppsFlyerEvents, MobileEventName } from 'uniswap/src/features/telemetry/constants' +import { MobileAppsFlyerEvents } from 'uniswap/src/features/telemetry/constants' import { sendAnalyticsEvent, sendAppsFlyerEvent } from 'uniswap/src/features/telemetry/send' -import { ImportType, OnboardingEntryPoint } from 'uniswap/src/types/onboarding' +import { OnboardingEntryPoint } from 'uniswap/src/types/onboarding' import { MobileScreens } from 'uniswap/src/types/screens/mobile' -import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' -import { - setHasSkippedUnitagPrompt, - setHasViewedUniconV2IntroModal, -} from 'wallet/src/features/behaviorHistory/slice' -import { pushNotification } from 'wallet/src/features/notifications/slice' -import { AppNotificationType } from 'wallet/src/features/notifications/types' -import { useClaimUnitag } from 'wallet/src/features/unitags/hooks' -import { Account, BackupType } from 'wallet/src/features/wallet/accounts/types' -import { - PendingAccountActions, - pendingAccountActions, -} from 'wallet/src/features/wallet/create/pendingAccountsSaga' -import { usePendingAccounts } from 'wallet/src/features/wallet/hooks' +import { useOnboardingContext } from 'wallet/src/features/onboarding/OnboardingContext' import { setFinishedOnboarding } from 'wallet/src/features/wallet/slice' export type OnboardingCompleteProps = OnboardingStackBaseParams @@ -33,68 +18,28 @@ export type OnboardingCompleteProps = OnboardingStackBaseParams export function useCompleteOnboardingCallback({ entryPoint, importType, - unitagClaim, }: OnboardingStackBaseParams): () => Promise { const dispatch = useAppDispatch() - const pendingAccounts = usePendingAccounts() - const pendingWalletAddresses = Object.keys(pendingAccounts) - const parentTrace = useTrace() + const { getAllOnboardingAccounts, finishOnboarding } = useOnboardingContext() const navigation = useOnboardingStackNavigation() - const claimUnitag = useClaimUnitag() - - const uniconsV2Enabled = useFeatureFlag(FeatureFlags.UniconsV2) + const onboardingAccounts = getAllOnboardingAccounts() + const onboardingAddresses = Object.keys(onboardingAccounts) return async () => { - sendAnalyticsEvent( - entryPoint === OnboardingEntryPoint.Sidebar - ? MobileEventName.WalletAdded - : MobileEventName.OnboardingCompleted, - { - wallet_type: importType, - accounts_imported_count: pendingWalletAddresses.length, - wallets_imported: pendingWalletAddresses, - cloud_backup_used: Object.values(pendingAccounts).some((acc: Account) => - acc.backups?.includes(BackupType.Cloud) - ), - ...parentTrace, - } - ) + // Run all shared onboarding completion logic + await finishOnboarding(importType) - // Log TOS acceptance for new wallets before they are activated + // Send appsflyer event for mobile attribution if (entryPoint === OnboardingEntryPoint.FreshInstallOrReplace) { - pendingWalletAddresses.forEach((address: string) => { - sendAnalyticsEvent(SharedEventName.TERMS_OF_SERVICE_ACCEPTED, { address }) - }) + await sendAppsFlyerEvent(MobileAppsFlyerEvents.OnboardingCompleted, { importType }) } - // Claim unitag if there's a claim to process - if (unitagClaim) { - const { claimError } = await claimUnitag(unitagClaim, { - source: 'onboarding', - hasENSAddress: false, + // Log TOS acceptance for new wallets after they are activated + if (entryPoint === OnboardingEntryPoint.FreshInstallOrReplace) { + onboardingAddresses.forEach((address: string) => { + sendAnalyticsEvent(SharedEventName.TERMS_OF_SERVICE_ACCEPTED, { address }) }) - if (claimError) { - dispatch( - pushNotification({ - type: AppNotificationType.Error, - errorMessage: claimError, - }) - ) - } - } - - // Remove pending flag from all new accounts. - dispatch(pendingAccountActions.trigger(PendingAccountActions.Activate)) - - // Dismiss unitags prompt if the onboarding method prompts for unitags (create new) - if (importType === ImportType.CreateNew) { - dispatch(setHasSkippedUnitagPrompt(true)) - } - - if (uniconsV2Enabled) { - // Don't show Unicon V2 intro modal to new users - dispatch(setHasViewedUniconV2IntroModal(true)) } // Exit flow @@ -102,9 +47,5 @@ export function useCompleteOnboardingCallback({ if (entryPoint === OnboardingEntryPoint.Sidebar) { navigation.navigate(MobileScreens.Home) } - - if (entryPoint === OnboardingEntryPoint.FreshInstallOrReplace) { - await sendAppsFlyerEvent(MobileAppsFlyerEvents.OnboardingCompleted, { importType }) - } } } diff --git a/apps/mobile/src/features/telemetry/saga.ts b/apps/mobile/src/features/telemetry/saga.ts index a9e50670381..9793cab7a61 100644 --- a/apps/mobile/src/features/telemetry/saga.ts +++ b/apps/mobile/src/features/telemetry/saga.ts @@ -5,6 +5,7 @@ import { selectAllowAnalytics } from 'src/features/telemetry/selectors' import { call, delay, fork, select, takeEvery } from 'typed-redux-saga' import { uniswapUrls } from 'uniswap/src/constants/urls' import { ApplicationTransport } from 'utilities/src/telemetry/analytics/ApplicationTransport' +// eslint-disable-next-line no-restricted-imports import { analytics } from 'utilities/src/telemetry/analytics/analytics' import { transactionActions } from 'wallet/src/features/transactions/slice' import { logTransactionEvent } from 'wallet/src/features/transactions/transactionWatcherSaga' @@ -14,12 +15,12 @@ export function* telemetrySaga() { const allowAnalytics = yield* select(selectAllowAnalytics) yield* call( analytics.init, - new ApplicationTransport( - uniswapUrls.amplitudeProxyUrl, - OriginApplication.MOBILE, - uniswapUrls.apiOrigin, - DeviceInfo.getBundleId() - ), + new ApplicationTransport({ + serverUrl: uniswapUrls.amplitudeProxyUrl, + appOrigin: OriginApplication.MOBILE, + originOverride: uniswapUrls.apiOrigin, + appBuild: DeviceInfo.getBundleId(), + }), allowAnalytics ) yield* fork(watchTransactionEvents) diff --git a/apps/mobile/src/features/telemetry/slice.ts b/apps/mobile/src/features/telemetry/slice.ts index 4e3fb142a0a..cf6ad0f686e 100644 --- a/apps/mobile/src/features/telemetry/slice.ts +++ b/apps/mobile/src/features/telemetry/slice.ts @@ -1,6 +1,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { SharedEventName } from '@uniswap/analytics-events' import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +// eslint-disable-next-line no-restricted-imports import { analytics } from 'utilities/src/telemetry/analytics/analytics' import { ONE_MINUTE_MS } from 'utilities/src/time/time' diff --git a/apps/mobile/src/features/unitags/ChooseProfilePictureScreen.tsx b/apps/mobile/src/features/unitags/ChooseProfilePictureScreen.tsx index e9d45baada4..ffa7068e23e 100644 --- a/apps/mobile/src/features/unitags/ChooseProfilePictureScreen.tsx +++ b/apps/mobile/src/features/unitags/ChooseProfilePictureScreen.tsx @@ -17,6 +17,7 @@ import { ChainId } from 'uniswap/src/types/chains' import { ImportType, OnboardingEntryPoint } from 'uniswap/src/types/onboarding' import { MobileScreens, OnboardingScreens, UnitagScreens } from 'uniswap/src/types/screens/mobile' import { useENSName } from 'wallet/src/features/ens/api' +import { useOnboardingContext } from 'wallet/src/features/onboarding/OnboardingContext' import { useClaimUnitag } from 'wallet/src/features/unitags/hooks' function convertEntryPointToAnalyticsSource(entryPoint: UnitagEntryPoint): UnitagClaimSource { @@ -48,6 +49,8 @@ export function ChooseProfilePictureScreen({ const [claimError, setClaimError] = useState() const [isClaiming, setIsClaiming] = useState(false) + const { addUnitagClaim } = useOnboardingContext() + const openModal = (): void => { setShowModal(true) } @@ -65,17 +68,13 @@ export function ChooseProfilePictureScreen({ const onPressContinue = async (): Promise => { if (entryPoint === OnboardingScreens.Landing) { + addUnitagClaim({ address, username: unitag, avatarUri: imageUri }) // Handle case navigating from onboarding navigate(MobileScreens.OnboardingStack, { screen: OnboardingScreens.WelcomeWallet, params: { importType: ImportType.CreateNew, entryPoint: OnboardingEntryPoint.FreshInstallOrReplace, - unitagClaim: { - address, - username: unitag, - avatarUri: imageUri, - }, }, }) } else { diff --git a/apps/mobile/src/features/unitags/ClaimUnitagScreen.tsx b/apps/mobile/src/features/unitags/ClaimUnitagScreen.tsx index 1e077adecdc..2b3fd659350 100644 --- a/apps/mobile/src/features/unitags/ClaimUnitagScreen.tsx +++ b/apps/mobile/src/features/unitags/ClaimUnitagScreen.tsx @@ -35,13 +35,16 @@ import { TextInput } from 'wallet/src/components/input/TextInput' import { WarningModal } from 'wallet/src/components/modals/WarningModal/WarningModal' import { LearnMoreLink } from 'wallet/src/components/text/LearnMoreLink' import { Pill } from 'wallet/src/components/text/Pill' +import { + useCreateOnboardingAccountIfNone, + useOnboardingContext, +} from 'wallet/src/features/onboarding/OnboardingContext' import { UNITAG_SUFFIX, UNITAG_SUFFIX_NO_LEADING_DOT, UNITAG_VALID_REGEX, } from 'wallet/src/features/unitags/constants' import { useCanClaimUnitagName } from 'wallet/src/features/unitags/hooks' -import { usePendingAccounts } from 'wallet/src/features/wallet/hooks' import { shortenAddress } from 'wallet/src/utils/addresses' import { useDynamicFontSizing } from 'wallet/src/utils/useDynamicFontSizing' @@ -67,13 +70,13 @@ export function ClaimUnitagScreen({ navigation, route }: Props): JSX.Element { useAddBackButton(navigation) const { t } = useTranslation() const colors = useSporeColors() + useCreateOnboardingAccountIfNone() + const { getOnboardingAccountAddress } = useOnboardingContext() + const onboardingAccountAddress = getOnboardingAccountAddress() const inputPlaceholder = getYourNameString(t('unitags.claim.username.default')) - // In onboarding flow, delete pending accounts and create account actions happen right before navigation - // So pendingAccountAddress must be fetched in this component and can't be passed in params - const pendingAccountAddress = Object.values(usePendingAccounts())?.[0]?.address - const unitagAddress = address || pendingAccountAddress + const unitagAddress = address || onboardingAccountAddress const [showInfoModal, setShowInfoModal] = useState(false) const [showClaimPeriodInfoModal, setShowClaimPeriodInfoModal] = useState(false) diff --git a/apps/mobile/src/features/walletConnect/signWcRequestSaga.ts b/apps/mobile/src/features/walletConnect/signWcRequestSaga.ts index 9c501e4ec49..c0391abb8d0 100644 --- a/apps/mobile/src/features/walletConnect/signWcRequestSaga.ts +++ b/apps/mobile/src/features/walletConnect/signWcRequestSaga.ts @@ -1,14 +1,20 @@ import { providers } from 'ethers' import { wcWeb3Wallet } from 'src/features/walletConnect/saga' +import { + TransactionRequest, + UwuLinkErc20Request, +} from 'src/features/walletConnect/walletConnectSlice' import { call, put } from 'typed-redux-saga' import { ChainId } from 'uniswap/src/types/chains' import { DappInfo, EthMethod, EthSignMethod, + UwULinkMethod, WalletConnectEvent, } from 'uniswap/src/types/walletConnect' import { logger } from 'utilities/src/logger/logger' +import { AssetType } from 'wallet/src/entities/assets' import { pushNotification } from 'wallet/src/features/notifications/slice' import { AppNotificationType } from 'wallet/src/features/notifications/types' import { @@ -39,6 +45,7 @@ type SignTransactionParams = { method: EthMethod.EthSendTransaction dapp: DappInfo chainId: ChainId + request: TransactionRequest | UwuLinkErc20Request } export function* signWcRequest(params: SignMessageParams | SignTransactionParams) { @@ -50,6 +57,26 @@ export function* signWcRequest(params: SignMessageParams | SignTransactionParams signature = yield* call(signMessage, params.message, account, signerManager) } else if (method === EthMethod.SignTypedData || method === EthMethod.SignTypedDataV4) { signature = yield* call(signTypedDataMessage, params.message, account, signerManager) + } else if ( + method === EthMethod.EthSendTransaction && + params.request.type === UwULinkMethod.Erc20Send + ) { + const txParams: SendTransactionParams = { + chainId: params.transaction.chainId || ChainId.Mainnet, + account, + options: { + request: params.transaction, + }, + typeInfo: { + type: TransactionType.Send, + assetType: AssetType.Currency, + recipient: params.request.recipient.address, + tokenAddress: params.request.tokenAddress, + currencyAmountRaw: params.request.amount, + }, + } + const { transactionResponse } = yield* call(sendTransaction, txParams) + signature = transactionResponse.hash } else if (method === EthMethod.EthSendTransaction) { const txParams: SendTransactionParams = { chainId: params.transaction.chainId || ChainId.Mainnet, diff --git a/apps/mobile/src/features/widgets/widgets.ts b/apps/mobile/src/features/widgets/widgets.ts index 0d4fe29f6fe..7e72b36bf38 100644 --- a/apps/mobile/src/features/widgets/widgets.ts +++ b/apps/mobile/src/features/widgets/widgets.ts @@ -6,6 +6,7 @@ import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { CurrencyId } from 'uniswap/src/types/currency' import { WidgetEvent } from 'uniswap/src/types/widgets' import { isAndroid } from 'uniswap/src/utils/platform' +// eslint-disable-next-line no-restricted-imports import { analytics } from 'utilities/src/telemetry/analytics/analytics' import { currencyIdToContractInput } from 'wallet/src/features/dataApi/utils' import { Account, AccountType } from 'wallet/src/features/wallet/accounts/types' diff --git a/apps/mobile/src/screens/DevScreen.tsx b/apps/mobile/src/screens/DevScreen.tsx index 621aaf26a78..6d1101f1018 100644 --- a/apps/mobile/src/screens/DevScreen.tsx +++ b/apps/mobile/src/screens/DevScreen.tsx @@ -12,23 +12,32 @@ import { UniconSampleSheet } from 'wallet/src/components/DevelopmentOnly/UniconS import { Switch } from 'wallet/src/components/buttons/Switch' import { pushNotification } from 'wallet/src/features/notifications/slice' import { AppNotificationType } from 'wallet/src/features/notifications/types' +import { createOnboardingAccount } from 'wallet/src/features/onboarding/createOnboardingAccount' import { resetDismissedWarnings } from 'wallet/src/features/tokens/tokensSlice' -import { createAccountActions } from 'wallet/src/features/wallet/create/createAccountSaga' +import { createAccountsActions } from 'wallet/src/features/wallet/create/createAccountsSaga' import { useActiveAccount } from 'wallet/src/features/wallet/hooks' +import { selectSortedSignerMnemonicAccounts } from 'wallet/src/features/wallet/selectors' import { resetWallet } from 'wallet/src/features/wallet/slice' +import { useAppSelector } from 'wallet/src/state' export function DevScreen(): JSX.Element { const insets = useDeviceInsets() const dispatch = useAppDispatch() const activeAccount = useActiveAccount() const [rtlEnabled, setRTLEnabled] = useState(I18nManager.isRTL) + const sortedMnemonicAccounts = useAppSelector(selectSortedSignerMnemonicAccounts) const onPressResetTokenWarnings = (): void => { dispatch(resetDismissedWarnings()) } - const onPressCreate = (): void => { - dispatch(createAccountActions.trigger()) + const onPressCreate = async (): Promise => { + dispatch( + createAccountsActions.trigger({ + accounts: [await createOnboardingAccount(sortedMnemonicAccounts)], + activateFirst: true, + }) + ) } const activateWormhole = (s: MobileScreens): void => { diff --git a/apps/mobile/src/screens/HomeScreen.tsx b/apps/mobile/src/screens/HomeScreen.tsx index e586e631dba..a73642d44fa 100644 --- a/apps/mobile/src/screens/HomeScreen.tsx +++ b/apps/mobile/src/screens/HomeScreen.tsx @@ -810,7 +810,7 @@ function ActionButton({ const iconSize = media.short ? iconSizes.icon24 : iconSizes.icon28 return ( - + (null) const dispatch = useAppDispatch() + const { generateImportedAccounts } = useOnboardingContext() const passwordAttemptCount = useAppSelector(selectPasswordAttempts) const lockoutEndTime = useAppSelector(selectLockoutEndTime) @@ -117,13 +117,8 @@ export function RestoreCloudBackupPasswordScreen({ async function checkCorrectPassword(): Promise { try { await restoreMnemonicFromCloudStorage(params.mnemonicId, enteredPassword) - dispatch( - importAccountActions.trigger({ - type: ImportAccountType.RestoreBackup, - mnemonicId: params.mnemonicId, - indexes: Array.from(Array(NUMBER_OF_WALLETS_TO_IMPORT).keys()), - }) - ) + await generateImportedAccounts(params.mnemonicId, BackupType.Cloud) + dispatch(resetPasswordAttempts()) // restore flow is handled in saga after `restoreMnemonicComplete` is dispatched if (!isRestoringMnemonic) { diff --git a/apps/mobile/src/screens/Import/SeedPhraseInputScreen.tsx b/apps/mobile/src/screens/Import/SeedPhraseInputScreen.tsx index 21d4973a2b4..c9d837f16d3 100644 --- a/apps/mobile/src/screens/Import/SeedPhraseInputScreen.tsx +++ b/apps/mobile/src/screens/Import/SeedPhraseInputScreen.tsx @@ -1,7 +1,6 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack' import React, { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' -import { useAppDispatch } from 'src/app/hooks' import { OnboardingStackParamList } from 'src/app/navigation/types' import { useLockScreenOnBlur } from 'src/features/authentication/lockScreenContext' import { GenericImportForm } from 'src/features/import/GenericImportForm' @@ -14,11 +13,10 @@ import Trace from 'uniswap/src/features/telemetry/Trace' import { ElementName } from 'uniswap/src/features/telemetry/constants' import { ImportType } from 'uniswap/src/types/onboarding' import { OnboardingScreens } from 'uniswap/src/types/screens/mobile' +import { useOnboardingContext } from 'wallet/src/features/onboarding/OnboardingContext' import { Keyring } from 'wallet/src/features/wallet/Keyring/Keyring' +import { BackupType } from 'wallet/src/features/wallet/accounts/types' import { useNonPendingSignerAccounts } from 'wallet/src/features/wallet/hooks' -import { importAccountActions } from 'wallet/src/features/wallet/import/importAccountSaga' -import { ImportAccountType } from 'wallet/src/features/wallet/import/types' -import { NUMBER_OF_WALLETS_TO_IMPORT } from 'wallet/src/features/wallet/import/utils' import { openUri } from 'wallet/src/utils/linking' import { MnemonicValidationError, @@ -31,8 +29,8 @@ import { type Props = NativeStackScreenProps export function SeedPhraseInputScreen({ navigation, route: { params } }: Props): JSX.Element { - const dispatch = useAppDispatch() const { t } = useTranslation() + const { generateImportedAccounts } = useOnboardingContext() /** * If paste permission modal is open, we need to manually disable the splash screen that appears on blur, @@ -64,6 +62,10 @@ export function SeedPhraseInputScreen({ navigation, route: { params } }: Props): return } + if (!validMnemonic) { + return + } + if (mnemonicId && validMnemonic) { const generatedMnemonicId = await Keyring.generateAddressForMnemonic(validMnemonic, 0) if (generatedMnemonicId !== mnemonicId) { @@ -72,18 +74,14 @@ export function SeedPhraseInputScreen({ navigation, route: { params } }: Props): } } - dispatch( - importAccountActions.trigger({ - type: ImportAccountType.Mnemonic, - validatedMnemonic: validMnemonic, - indexes: Array.from(Array(NUMBER_OF_WALLETS_TO_IMPORT).keys()), - }) - ) + const importedMnemonicId = await Keyring.importMnemonic(validMnemonic) + await generateImportedAccounts(importedMnemonicId, BackupType.Manual) + // restore flow is handled in saga after `restoreMnemonicComplete` is dispatched if (!isRestoringMnemonic) { navigation.navigate({ name: OnboardingScreens.SelectWallet, params, merge: true }) } - }, [value, mnemonicId, dispatch, isRestoringMnemonic, t, navigation, params]) + }, [value, mnemonicId, generateImportedAccounts, isRestoringMnemonic, t, navigation, params]) const onBlur = useCallback(() => { const { error, invalidWord } = validateMnemonic(value) diff --git a/apps/mobile/src/screens/Import/SeedPhraseInputScreenV2.tsx b/apps/mobile/src/screens/Import/SeedPhraseInputScreenV2.tsx index c27b5297c1c..3916ea021f7 100644 --- a/apps/mobile/src/screens/Import/SeedPhraseInputScreenV2.tsx +++ b/apps/mobile/src/screens/Import/SeedPhraseInputScreenV2.tsx @@ -2,7 +2,6 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack' import React, { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { NativeSyntheticEvent } from 'react-native' -import { useAppDispatch } from 'src/app/hooks' import { OnboardingStackParamList } from 'src/app/navigation/types' import { useLockScreenOnBlur } from 'src/features/authentication/lockScreenContext' import { SafeKeyboardOnboardingScreen } from 'src/features/onboarding/SafeKeyboardOnboardingScreen' @@ -20,17 +19,16 @@ import Trace from 'uniswap/src/features/telemetry/Trace' import { ElementName } from 'uniswap/src/features/telemetry/constants' import { ImportType } from 'uniswap/src/types/onboarding' import { OnboardingScreens } from 'uniswap/src/types/screens/mobile' +import { useOnboardingContext } from 'wallet/src/features/onboarding/OnboardingContext' +import { BackupType } from 'wallet/src/features/wallet/accounts/types' import { useNonPendingSignerAccounts } from 'wallet/src/features/wallet/hooks' -import { importAccountActions } from 'wallet/src/features/wallet/import/importAccountSaga' -import { ImportAccountType } from 'wallet/src/features/wallet/import/types' -import { NUMBER_OF_WALLETS_TO_IMPORT } from 'wallet/src/features/wallet/import/utils' import { openUri } from 'wallet/src/utils/linking' type Props = NativeStackScreenProps export function SeedPhraseInputScreenV2({ navigation, route: { params } }: Props): JSX.Element { - const dispatch = useAppDispatch() const { t } = useTranslation() + const { generateImportedAccounts } = useOnboardingContext() /** * If paste permission modal is open, we need to manually disable the splash screen that appears on blur, @@ -52,21 +50,15 @@ export function SeedPhraseInputScreenV2({ navigation, route: { params } }: Props const targetMnemonicId = (isRestoringMnemonic && signerAccounts[0]?.mnemonicId) || undefined const handleNext = useCallback( - (storedMnemonicId: string) => { - dispatch( - importAccountActions.trigger({ - type: ImportAccountType.MnemonicNative, - mnemonicId: storedMnemonicId, - indexes: Array.from(Array(NUMBER_OF_WALLETS_TO_IMPORT).keys()), - }) - ) + async (storedMnemonicId: string) => { + await generateImportedAccounts(storedMnemonicId, BackupType.Manual) // restore flow is handled in saga after `restoreMnemonicComplete` is dispatched if (!isRestoringMnemonic) { navigation.navigate({ name: OnboardingScreens.SelectWallet, params, merge: true }) } }, - [dispatch, isRestoringMnemonic, navigation, params] + [generateImportedAccounts, isRestoringMnemonic, navigation, params] ) const onPressRecoveryHelpButton = (): Promise => @@ -108,7 +100,7 @@ export function SeedPhraseInputScreenV2({ navigation, route: { params } }: Props onInputValidated={(e: NativeSyntheticEvent): void => setSubmitEnabled(e.nativeEvent.canSubmit) } - onMnemonicStored={(e: NativeSyntheticEvent): void => + onMnemonicStored={(e: NativeSyntheticEvent): Promise => handleNext(e.nativeEvent.mnemonicId) } onPasteEnd={(): void => { diff --git a/apps/mobile/src/screens/Import/SelectWalletScreen.tsx b/apps/mobile/src/screens/Import/SelectWalletScreen.tsx index 4c22f0a98a5..dcd1fad85bc 100644 --- a/apps/mobile/src/screens/Import/SelectWalletScreen.tsx +++ b/apps/mobile/src/screens/Import/SelectWalletScreen.tsx @@ -1,8 +1,8 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack' -import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react' +import { isEqual } from 'lodash' +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { ScrollView } from 'react-native-gesture-handler' -import { useAppDispatch } from 'src/app/hooks' import { OnboardingStackParamList } from 'src/app/navigation/types' import { OnboardingScreen } from 'src/features/onboarding/OnboardingScreen' import { Button, Flex, Loader } from 'ui/src' @@ -14,18 +14,13 @@ import { ONE_SECOND_MS } from 'utilities/src/time/time' import { useTimeout } from 'utilities/src/time/timing' import { BaseCard } from 'wallet/src/components/BaseCard/BaseCard' import WalletPreviewCard from 'wallet/src/components/WalletPreviewCard/WalletPreviewCard' -import { - EditAccountAction, - editAccountActions, -} from 'wallet/src/features/wallet/accounts/editAccountSaga' -import { AccountType, SignerMnemonicAccount } from 'wallet/src/features/wallet/accounts/types' +import { useOnboardingContext } from 'wallet/src/features/onboarding/OnboardingContext' import { PendingAccountActions, pendingAccountActions, } from 'wallet/src/features/wallet/create/pendingAccountsSaga' -import { usePendingAccounts } from 'wallet/src/features/wallet/hooks' import { NUMBER_OF_WALLETS_TO_IMPORT } from 'wallet/src/features/wallet/import/utils' -import { setAccountAsActive } from 'wallet/src/features/wallet/slice' +import { useAppDispatch } from 'wallet/src/state' const FORCED_LOADING_DURATION = 3 * ONE_SECOND_MS // 3s @@ -46,27 +41,23 @@ type Props = NativeStackScreenProps a.type === AccountType.SignerMnemonic) - .sort( - (a, b) => - (a as SignerMnemonicAccount).derivationIndex - (b as SignerMnemonicAccount).derivationIndex - ) - .map((account) => account.address) + if (!importedAccountsAddresses) { + throw new Error('There are no imported accounts addresses available on SelectWalletScreen') + } - const isImportingAccounts = addresses.length !== NUMBER_OF_WALLETS_TO_IMPORT + const isImportingAccounts = importedAccountsAddresses.length !== NUMBER_OF_WALLETS_TO_IMPORT const { data, loading, refetch, error } = useSelectWalletScreenQuery({ - variables: { ownerAddresses: addresses }, + variables: { ownerAddresses: importedAccountsAddresses }, /* * Wait until all the addresses have been added to the store before querying. * Also prevents an extra API call when user navigates back and clears pending accounts. */ skip: isImportingAccounts, }) - const onRetry = useCallback(() => refetch(), [refetch]) const allAddressBalances = data?.portfolios @@ -94,11 +85,11 @@ export function SelectWalletScreen({ navigation, route: { params } }: Props): JS } // if query for address balances returned null, show the first address - const firstPendingAddress = addresses[0] + const firstPendingAddress = importedAccountsAddresses[0] if (firstPendingAddress) { return [{ ownerAddress: firstPendingAddress, balance: undefined }] } - }, [addresses, allAddressBalances]) + }, [importedAccountsAddresses, allAddressBalances]) const initialSelectedAddresses = useMemo( () => @@ -112,13 +103,20 @@ export function SelectWalletScreen({ navigation, route: { params } }: Props): JS const showError = error && !initialShownAccounts?.length - const [selectedAddresses, setSelectedAddresses] = useReducer( - (currentAddresses: string[], addressToProcess: string) => - currentAddresses.includes(addressToProcess) - ? currentAddresses.filter((address) => address !== addressToProcess) - : [...currentAddresses, addressToProcess], - initialSelectedAddresses - ) + const [selectedAddresses, setSelectedAddresses] = useState(initialSelectedAddresses) + + // stores the last value of data extracted from useSelectWalletScreenQuery + const initialSelectedAddressesRef = useRef(initialSelectedAddresses) + + // selects all accounts in case when useSelectWalletScreenQuery returns extra accounts + // after selectedAddresses useState initialization + useEffect(() => { + if (isEqual(initialSelectedAddressesRef.current, initialSelectedAddresses)) { + return + } + initialSelectedAddressesRef.current = initialSelectedAddresses + setSelectedAddresses(initialSelectedAddresses) + }, [initialSelectedAddresses]) useEffect(() => { const beforeRemoveListener = (): void => { @@ -127,56 +125,24 @@ export function SelectWalletScreen({ navigation, route: { params } }: Props): JS } navigation.addListener('beforeRemove', beforeRemoveListener) return () => navigation.removeListener('beforeRemove', beforeRemoveListener) - }, [dispatch, navigation, pendingAccounts]) - - useEffect(() => { - /* - * In the event that the initial state of `selectedAddresses` is empty due to - * delay in importAccountSaga, we need to set the fallback account as selected - */ - if (isImportingAccounts || loading || selectedAddresses.length > 0) { - return - } - - initialSelectedAddresses.forEach((address) => setSelectedAddresses(address)) - }, [initialSelectedAddresses, isImportingAccounts, loading, selectedAddresses.length]) + }, [dispatch, navigation]) const onPress = (address: string): void => { - if (initialShownAccounts?.length === 1 && selectedAddresses.length === 1) { + // prevents the last selected wallet from being deselected + if (selectedAddresses.length === 1 && selectedAddresses.includes(address)) { return } - setSelectedAddresses(address) + if (selectedAddresses.includes(address)) { + setSelectedAddresses( + selectedAddresses.filter((selectedAddress) => selectedAddress !== address) + ) + } else { + setSelectedAddresses([...selectedAddresses, address]) + } } - const isFirstAccountActive = useRef(false) // to keep track of first account activated from the selected accounts const onSubmit = useCallback(() => { - addresses.forEach((address) => { - // Remove unselected accounts from store. - if (!selectedAddresses.includes(address)) { - dispatch( - editAccountActions.trigger({ - type: EditAccountAction.Remove, - address, - notificationsEnabled: !!pendingAccounts[address]?.pushNotificationsEnabled, - }) - ) - } else { - if (!isFirstAccountActive.current) { - dispatch(setAccountAsActive(address)) - isFirstAccountActive.current = true - } - const account = pendingAccounts[address] - if (account && !account.name && account.type !== AccountType.Readonly) { - dispatch( - editAccountActions.trigger({ - type: EditAccountAction.Rename, - address, - newName: t('onboarding.wallet.defaultName', { number: account.derivationIndex + 1 }), - }) - ) - } - } - }) + selectImportedAccounts(selectedAddresses) navigation.navigate({ name: @@ -186,7 +152,7 @@ export function SelectWalletScreen({ navigation, route: { params } }: Props): JS params, merge: true, }) - }, [addresses, navigation, params, selectedAddresses, dispatch, pendingAccounts, t]) + }, [selectImportedAccounts, selectedAddresses, navigation, params]) // Force a fixed duration loading state for smoother transition (as we show different UI for 1 vs multiple wallets) const [isForcedLoading, setIsForcedLoading] = useState(true) diff --git a/apps/mobile/src/screens/Import/WatchWalletScreen.tsx b/apps/mobile/src/screens/Import/WatchWalletScreen.tsx index 67e0b95ebac..cbca60c4cf2 100644 --- a/apps/mobile/src/screens/Import/WatchWalletScreen.tsx +++ b/apps/mobile/src/screens/Import/WatchWalletScreen.tsx @@ -1,7 +1,7 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack' import { SharedEventName } from '@uniswap/analytics-events' import { TFunction } from 'i18next' -import React, { useCallback, useEffect, useState } from 'react' +import React, { useCallback, useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { Keyboard } from 'react-native' import { useAppDispatch } from 'src/app/hooks' @@ -23,7 +23,7 @@ import { useIsSmartContractAddress } from 'wallet/src/features/transactions/tran import { useAccounts } from 'wallet/src/features/wallet/hooks' import { importAccountActions } from 'wallet/src/features/wallet/import/importAccountSaga' import { ImportAccountType } from 'wallet/src/features/wallet/import/types' -import { getValidAddress } from 'wallet/src/utils/addresses' +import { areAddressesEqual, getValidAddress } from 'wallet/src/utils/addresses' type Props = NativeStackScreenProps @@ -77,7 +77,7 @@ export function WatchWalletScreen({ navigation, route: { params } }: Props): JSX const dispatch = useAppDispatch() const { t } = useTranslation() const accounts = useAccounts() - const importedAddresses = Object.keys(accounts) + const initialAccounts = useRef(accounts) useAddBackButton(navigation) @@ -107,10 +107,13 @@ export function WatchWalletScreen({ navigation, route: { params } }: Props): JSX const onCompleteOnboarding = useCompleteOnboardingCallback(params) + const walletExists = Object.keys(initialAccounts).some( + (accountAddress) => + areAddressesEqual(accountAddress, resolvedAddress) || + areAddressesEqual(accountAddress, normalizedValue) + ) + // Form validation. - const walletExists = - (resolvedAddress && importedAddresses.includes(resolvedAddress)) || - importedAddresses.includes(normalizedValue) const isValid = validateForm({ isAddress, name, @@ -126,21 +129,13 @@ export function WatchWalletScreen({ navigation, route: { params } }: Props): JSX const onSubmit = useCallback(async () => { if (isValid && value) { - if (resolvedAddress) { - dispatch( - importAccountActions.trigger({ - type: ImportAccountType.Address, - address: resolvedAddress, - }) - ) - } else { - dispatch( - importAccountActions.trigger({ - type: ImportAccountType.Address, - address: normalizedValue, - }) - ) - } + dispatch( + importAccountActions.trigger({ + type: ImportAccountType.Address, + address: resolvedAddress || normalizedValue, + }) + ) + sendAnalyticsEvent(SharedEventName.ELEMENT_CLICKED, { screen: OnboardingScreens.WatchWallet, element: ElementName.Continue, diff --git a/apps/mobile/src/screens/NFTItemScreen.tsx b/apps/mobile/src/screens/NFTItemScreen.tsx index 7ff1b6bdf1d..c6a2252bb2f 100644 --- a/apps/mobile/src/screens/NFTItemScreen.tsx +++ b/apps/mobile/src/screens/NFTItemScreen.tsx @@ -36,11 +36,15 @@ import { } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' import Trace from 'uniswap/src/features/telemetry/Trace' import { ModalName } from 'uniswap/src/features/telemetry/constants' +import { ChainId } from 'uniswap/src/types/chains' import { MobileScreens } from 'uniswap/src/types/screens/mobile' import { isAndroid, isIOS } from 'uniswap/src/utils/platform' import { BaseCard } from 'wallet/src/components/BaseCard/BaseCard' +import { NetworkLogo } from 'wallet/src/components/CurrencyLogo/NetworkLogo' import { AddressDisplay } from 'wallet/src/components/accounts/AddressDisplay' +import { CHAIN_INFO } from 'wallet/src/constants/chains' import { PollingInterval } from 'wallet/src/constants/misc' +import { fromGraphQLChain } from 'wallet/src/features/chains/utils' import { NFTViewer } from 'wallet/src/features/images/NFTViewer' import { GQLNftAsset } from 'wallet/src/features/nfts/hooks' import { useNFTContextMenu } from 'wallet/src/features/nfts/useNftContextMenu' @@ -101,6 +105,7 @@ function NFTItemScreenContents({ }) const asset = data?.nftAssets?.edges[0]?.node const owner = (ownerFromProps || asset?.ownerAddress) ?? undefined + const chainId = fromGraphQLChain(fallbackData?.chain) ?? undefined const lastSaleData = data?.nftActivity?.edges[0]?.node const listingPrice = asset?.listings?.edges?.[0]?.node?.price @@ -298,6 +303,7 @@ function NFTItemScreenContents({ collection={asset?.collection} fallbackData={fallbackData} loading={nftLoading} + shouldDisableLink={chainId !== ChainId.Mainnet} // TODO(MOB-3447): Remove once backend has full L2 collection support onPress={onPressCollection} /> @@ -333,6 +339,20 @@ function NFTItemScreenContents({ } /> ) : null} + {chainId && ( + + + {CHAIN_INFO[chainId].label} + + + + } + /> + )} {lastSaleData?.price?.value ? ( { navigation.navigate({ name: OnboardingScreens.Notifications, - params: { importType, entryPoint, unitagClaim }, + params: { importType, entryPoint }, merge: true, }) } @@ -28,7 +28,7 @@ export function CloudBackupProcessingScreen({ const onErrorPress = (): void => { navigation.navigate({ name: OnboardingScreens.Backup, - params: { importType, entryPoint, unitagClaim }, + params: { importType, entryPoint }, merge: true, }) } diff --git a/apps/mobile/src/screens/Onboarding/LandingScreen.tsx b/apps/mobile/src/screens/Onboarding/LandingScreen.tsx index a74a36a4e02..6d4e87952bc 100644 --- a/apps/mobile/src/screens/Onboarding/LandingScreen.tsx +++ b/apps/mobile/src/screens/Onboarding/LandingScreen.tsx @@ -21,11 +21,6 @@ import { isDevEnv } from 'uniswap/src/utils/env' import { ONE_SECOND_MS } from 'utilities/src/time/time' import { useTimeout } from 'utilities/src/time/timing' import { useCanAddressClaimUnitag } from 'wallet/src/features/unitags/hooks' -import { createAccountActions } from 'wallet/src/features/wallet/create/createAccountSaga' -import { - PendingAccountActions, - pendingAccountActions, -} from 'wallet/src/features/wallet/create/pendingAccountsSaga' type Props = NativeStackScreenProps @@ -50,9 +45,6 @@ export function LandingScreen({ navigation }: Props): JSX.Element { const { canClaimUnitag } = useCanAddressClaimUnitag() const onPressCreateWallet = useCallback((): void => { - dispatch(pendingAccountActions.trigger(PendingAccountActions.Delete)) - dispatch(createAccountActions.trigger()) - if (canClaimUnitag) { navigation.navigate(UnitagScreens.ClaimUnitag, { entryPoint: OnboardingScreens.Landing, @@ -64,7 +56,7 @@ export function LandingScreen({ navigation }: Props): JSX.Element { entryPoint: OnboardingEntryPoint.FreshInstallOrReplace, }) } - }, [canClaimUnitag, dispatch, navigation]) + }, [canClaimUnitag, navigation]) const onPressImportWallet = (): void => { navigation.navigate(OnboardingScreens.ImportMethod, { diff --git a/apps/mobile/src/screens/Onboarding/ManualBackupScreen.tsx b/apps/mobile/src/screens/Onboarding/ManualBackupScreen.tsx index 3399e7cb46b..1f2080a68eb 100644 --- a/apps/mobile/src/screens/Onboarding/ManualBackupScreen.tsx +++ b/apps/mobile/src/screens/Onboarding/ManualBackupScreen.tsx @@ -3,7 +3,6 @@ import { SharedEventName } from '@uniswap/analytics-events' import { addScreenshotListener } from 'expo-screen-capture' import React, { useEffect, useReducer, useState } from 'react' import { useTranslation } from 'react-i18next' -import { useAppDispatch } from 'src/app/hooks' import { OnboardingStackParamList } from 'src/app/navigation/types' import { HiddenMnemonicWordView } from 'src/components/mnemonic/HiddenMnemonicWordView' import { MnemonicConfirmation } from 'src/components/mnemonic/MnemonicConfirmation' @@ -18,12 +17,8 @@ import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { ManualPageViewScreen, OnboardingScreens } from 'uniswap/src/types/screens/mobile' import { BottomSheetModal } from 'wallet/src/components/modals/BottomSheetModal' import { WarningModal } from 'wallet/src/components/modals/WarningModal/WarningModal' -import { - EditAccountAction, - editAccountActions, -} from 'wallet/src/features/wallet/accounts/editAccountSaga' -import { BackupType, SignerMnemonicAccount } from 'wallet/src/features/wallet/accounts/types' -import { useActiveAccount } from 'wallet/src/features/wallet/hooks' +import { useOnboardingContext } from 'wallet/src/features/onboarding/OnboardingContext' +import { BackupType } from 'wallet/src/features/wallet/accounts/types' type Props = NativeStackScreenProps @@ -34,13 +29,17 @@ enum View { export function ManualBackupScreen({ navigation, route: { params } }: Props): JSX.Element | null { const { t } = useTranslation() - const dispatch = useAppDispatch() const media = useMedia() + const { getOnboardingAccount, addBackupMethod } = useOnboardingContext() + const onboardingAccount = getOnboardingAccount() useLockScreenOnBlur() - const activeAccount = useActiveAccount() - const mnemonicId = (activeAccount as SignerMnemonicAccount)?.mnemonicId + if (!onboardingAccount) { + throw Error('pendingAccount needs to be defined on ManualBackupScreen') + } + + const mnemonicId = onboardingAccount.mnemonicId const [showScreenShotWarningModal, setShowScreenShotWarningModal] = useState(false) const [view, nextView] = useReducer((curView: View) => curView + 1, View.SeedPhrase) @@ -52,16 +51,8 @@ export function ManualBackupScreen({ navigation, route: { params } }: Props): JS const [seedWarningAcknowledged, setSeedWarningAcknowledged] = useState(false) const onValidationSuccessful = (): void => { - if (activeAccount) { - setContinueButtonPressed(true) - dispatch( - editAccountActions.trigger({ - type: EditAccountAction.AddBackupMethod, - address: activeAccount.address, - backupMethod: BackupType.Manual, - }) - ) - } + setContinueButtonPressed(true) + addBackupMethod(BackupType.Manual) } useEffect(() => { @@ -74,10 +65,10 @@ export function ManualBackupScreen({ navigation, route: { params } }: Props): JS }, [view]) useEffect(() => { - if (continueButtonPressed && activeAccount?.backups?.includes(BackupType.Manual)) { + if (continueButtonPressed && onboardingAccount?.backups?.includes(BackupType.Manual)) { navigation.navigate({ name: OnboardingScreens.Notifications, params, merge: true }) } - }, [continueButtonPressed, activeAccount?.backups, navigation, params]) + }, [continueButtonPressed, navigation, params, onboardingAccount?.backups]) // Manually log as page views as these screens are not captured in navigation events useEffect(() => { diff --git a/apps/mobile/src/screens/Onboarding/NotificationsSetupScreen.tsx b/apps/mobile/src/screens/Onboarding/NotificationsSetupScreen.tsx index 41181b89903..868cab3436f 100644 --- a/apps/mobile/src/screens/Onboarding/NotificationsSetupScreen.tsx +++ b/apps/mobile/src/screens/Onboarding/NotificationsSetupScreen.tsx @@ -2,7 +2,6 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack' import React, { useCallback, useEffect } from 'react' import { useTranslation } from 'react-i18next' import { Alert, Image, Platform, StyleSheet } from 'react-native' -import { useAppDispatch, useAppSelector } from 'src/app/hooks' import { OnboardingStackParamList } from 'src/app/navigation/types' import { BackButton } from 'src/components/buttons/BackButton' import { useBiometricContext } from 'src/features/biometrics/context' @@ -18,12 +17,8 @@ import i18n from 'uniswap/src/i18n/i18n' import { ImportType, OnboardingEntryPoint } from 'uniswap/src/types/onboarding' import { OnboardingScreens } from 'uniswap/src/types/screens/mobile' import { isIOS } from 'uniswap/src/utils/platform' -import { - EditAccountAction, - editAccountActions, -} from 'wallet/src/features/wallet/accounts/editAccountSaga' +import { useOnboardingContext } from 'wallet/src/features/onboarding/OnboardingContext' import { useNativeAccountExists } from 'wallet/src/features/wallet/hooks' -import { selectAccounts } from 'wallet/src/features/wallet/selectors' import { openSettings } from 'wallet/src/utils/linking' type Props = NativeStackScreenProps @@ -44,11 +39,9 @@ export const showNotificationSettingsAlert = (): void => { export function NotificationsSetupScreen({ navigation, route: { params } }: Props): JSX.Element { const { t } = useTranslation() const { requiredForTransactions: isBiometricAuthEnabled } = useBiometricAppSettings() - const accounts = useAppSelector(selectAccounts) - const dispatch = useAppDispatch() - const addresses = Object.keys(accounts) const hasSeedPhrase = useNativeAccountExists() const { deviceSupportsBiometrics } = useBiometricContext() + const { enableNotifications } = useOnboardingContext() const onCompleteOnboarding = useCompleteOnboardingCallback(params) @@ -103,19 +96,11 @@ export function NotificationsSetupScreen({ navigation, route: { params } }: Prop const onPressEnableNotifications = useCallback(async () => { promptPushPermission(() => { - addresses.forEach((address) => { - dispatch( - editAccountActions.trigger({ - type: EditAccountAction.TogglePushNotification, - enabled: true, - address, - }) - ) - }) + enableNotifications() }, showNotificationSettingsAlert) await navigateToNextScreen() - }, [addresses, dispatch, navigateToNextScreen]) + }, [enableNotifications, navigateToNextScreen]) return ( { @@ -63,23 +72,23 @@ export function WelcomeWalletScreen({ navigation, route: { params } }: Props): J const zeroBalance = convertFiatAmountFormatted(0, NumberType.PortfolioBalance) - const displayName = params.unitagClaim - ? { type: DisplayNameType.Unitag, name: params.unitagClaim.username } + const displayName = unitagClaim + ? { type: DisplayNameType.Unitag, name: unitagClaim.username } : walletName return ( - {params.unitagClaim?.avatarUri ? ( + {unitagClaim?.avatarUri ? ( ) : ( - - - {t('settings.setting.wallet.action.editLabel')} - - - - - - {showEditButton && accountNameIsEditable && ( - - - - + + ) } diff --git a/apps/web/.eslintrc.js b/apps/web/.eslintrc.js index 3442fc852b2..2af92ddab46 100644 --- a/apps/web/.eslintrc.js +++ b/apps/web/.eslintrc.js @@ -77,6 +77,11 @@ module.exports = { message: 'Importing isIOS and isAndroid from platform is not allowed. Use isWebIOS and isWebAndroid instead.', }, + { + name: 'wagmi', + importNames: ['useChainId', 'useAccount'], + message: 'Import properly typed account data from `hooks/useAccount` instead.', + }, ], }, ], @@ -108,20 +113,7 @@ module.exports = { { files: ['**/*.ts', '**/*.tsx'], excludedFiles: ['src/analytics/*'], - rules: { - // Uses 'no-restricted-imports' to avoid overriding the above rules in '@typescript-eslint/no-restricted-imports' - 'no-restricted-imports': [ - 'error', - { - paths: [ - { - name: '@uniswap/analytics', - message: `Do not import from '@uniswap/analytics' directly. Use 'analytics' instead.`, - }, - ], - }, - ], - }, + rules: {}, }, ], } diff --git a/apps/web/cypress/e2e/remove-liquidity.test.ts b/apps/web/cypress/e2e/remove-liquidity.test.ts index b09f021ed0b..d13fc4043c2 100644 --- a/apps/web/cypress/e2e/remove-liquidity.test.ts +++ b/apps/web/cypress/e2e/remove-liquidity.test.ts @@ -1,10 +1,13 @@ import { ChainId, MaxUint256, UNI_ADDRESSES } from '@uniswap/sdk-core' +import { FeatureFlags } from 'uniswap/src/features/gating/flags' const UNI_MAINNET = UNI_ADDRESSES[ChainId.MAINNET] describe('Remove Liquidity', () => { it('loads the token pair in v2', () => { - cy.visit(`/remove/v2/ETH/${UNI_MAINNET}`) + cy.visit(`/remove/v2/ETH/${UNI_MAINNET}`, { + featureFlags: [{ flag: FeatureFlags.V2Everywhere, value: true }], + }) cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'ETH') cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'UNI') }) diff --git a/apps/web/cypress/e2e/swap/fees.test.ts b/apps/web/cypress/e2e/swap/fees.test.ts index 86056d3853c..7f4be5a6fd7 100644 --- a/apps/web/cypress/e2e/swap/fees.test.ts +++ b/apps/web/cypress/e2e/swap/fees.test.ts @@ -11,7 +11,9 @@ describe('Swap with fees', () => { // Store trade quote into alias cy.intercept({ url: 'https://interface.gateway.uniswap.org/v2/quote' }, (req) => { // Avoid tracking stablecoin pricing fetches - if (JSON.parse(req.body).intent !== 'pricing') req.alias = 'quoteFetch' + if (JSON.parse(req.body).intent !== 'pricing') { + req.alias = 'quoteFetch' + } }) }) @@ -42,7 +44,9 @@ describe('Swap with fees', () => { .then(({ quote: { portionBips, portionRecipient, portionAmount } }) => { // Fees are generally expected to always be enabled for ETH -> USDC swaps // If the routing api does not include a fee, end the test early rather than manually update routes and hardcode fee vars - if (portionRecipient) return + if (portionRecipient) { + return + } cy.then(() => hardhat.getBalance(portionRecipient, USDC_MAINNET)).then((initialRecipientBalance) => { const feeCurrencyAmount = CurrencyAmount.fromRawAmount(USDC_MAINNET, portionAmount) @@ -89,7 +93,9 @@ describe('Swap with fees', () => { .then(({ quote: { portionBips, portionRecipient } }) => { // Fees are generally expected to always be enabled for ETH -> USDC swaps // If the routing api does not include a fee, end the test early rather than manually update routes and hardcode fee vars - if (portionRecipient) return + if (portionRecipient) { + return + } cy.then(() => hardhat.getBalance(portionRecipient, USDC_MAINNET)).then((initialRecipientBalance) => { // Initiate transaction diff --git a/apps/web/cypress/e2e/swap/uniswapx.test.ts b/apps/web/cypress/e2e/swap/uniswapx.test.ts index 244c0f4c20c..3e045f9df0c 100644 --- a/apps/web/cypress/e2e/swap/uniswapx.test.ts +++ b/apps/web/cypress/e2e/swap/uniswapx.test.ts @@ -292,15 +292,7 @@ describe('UniswapX v1', () => { submitUniswapXOrder() cy.get(getTestSelector('confirmation-close-icon')).click() - cy.intercept(/(?:interface|beta).gateway.uniswap.org\/v1\/graphql/, (req) => { - if (req.body.operationName === 'PortfolioBalancesWeb') { - req.alias = 'PortfolioBalancesWeb' - // Reply with a fixture to speed up test - req.reply({ fixture: 'mini-portfolio/tokens.json' }) - } else { - req.continue() - } - }) + cy.interceptGraphqlOperation('PortfolioBalancesWeb', 'mini-portfolio/tokens.json') // Expect balances to refetch after filling cy.wait('@orderStatusOpen') diff --git a/apps/web/cypress/e2e/swap/uniswapxv2.test.ts b/apps/web/cypress/e2e/swap/uniswapxv2.test.ts index ff9ae653f98..0f3e7afccb3 100644 --- a/apps/web/cypress/e2e/swap/uniswapxv2.test.ts +++ b/apps/web/cypress/e2e/swap/uniswapxv2.test.ts @@ -287,15 +287,7 @@ describe('UniswapX v2', () => { submitUniswapXOrder() cy.get(getTestSelector('confirmation-close-icon')).click() - cy.intercept(/(?:interface|beta).gateway.uniswap.org\/v1\/graphql/, (req) => { - if (req.body.operationName === 'PortfolioBalancesWeb') { - req.alias = 'PortfolioBalancesWeb' - // Reply with a fixture to speed up test - req.reply({ fixture: 'mini-portfolio/tokens.json' }) - } else { - req.continue() - } - }) + cy.interceptGraphqlOperation('PortfolioBalancesWeb', 'mini-portfolio/tokens.json') // Expect balances to refetch after filling cy.wait('@orderStatusOpen') diff --git a/apps/web/cypress/e2e/token-details.test.ts b/apps/web/cypress/e2e/token-details.test.ts index b52abfce52f..2219707003c 100644 --- a/apps/web/cypress/e2e/token-details.test.ts +++ b/apps/web/cypress/e2e/token-details.test.ts @@ -80,9 +80,10 @@ describe('Token details', () => { cy.contains(shortenAddress('0x1eFBB78C8b917f67986BcE54cE575069c0143681')).should('exist') // Warning label should show if relevant ([spec](https://www.notion.so/3f7fce6f93694be08a94a6984d50298e)) - cy.get('[data-cy="token-safety-message"]') - .should('include.text', 'Warning') - .and('include.text', "This token isn't traded on leading U.S. centralized exchanges") + cy.get('[data-cy="token-safety-message"]').contains(/Warning/) + cy.get('[data-cy="token-safety-description"]').contains( + /This token isn’t traded on leading U.S. centralized exchanges or frequently swapped on Uniswap./ + ) }) describe('swapping', () => { diff --git a/apps/web/cypress/support/commands.ts b/apps/web/cypress/support/commands.ts index 6157a2bb42f..44bc9c99b52 100644 --- a/apps/web/cypress/support/commands.ts +++ b/apps/web/cypress/support/commands.ts @@ -56,7 +56,9 @@ declare global { Cypress.Commands.overwrite( 'visit', (original, url: string | Partial, options?: Partial) => { - if (typeof url !== 'string') throw new Error('Invalid arguments. The first argument to cy.visit must be the path.') + if (typeof url !== 'string') { + throw new Error('Invalid arguments. The first argument to cy.visit must be the path.') + } // Parse overrides const flagsOn: FeatureFlags[] = [] @@ -113,7 +115,9 @@ Cypress.Commands.add('waitForAmplitudeEvent', (eventName, requiredProperties) => function findAndDiscardEventsUpToTarget() { const events = Cypress.env('amplitudeEventCache') const targetEventIndex = events.findIndex((event) => { - if (event.event_type !== eventName) return false + if (event.event_type !== eventName) { + return false + } if (requiredProperties) { return requiredProperties.every((prop) => event.event_properties[prop]) } diff --git a/apps/web/cypress/support/e2e.ts b/apps/web/cypress/support/e2e.ts index bb1377bfc4d..c6345ce169f 100644 --- a/apps/web/cypress/support/e2e.ts +++ b/apps/web/cypress/support/e2e.ts @@ -13,7 +13,9 @@ import './setupTests' // TODO(https://github.com/cypress-io/cypress/issues/26069): Squelch only wildcard logs once Cypress allows it. const log = Cypress.log Cypress.log = function (options, ...args) { - if (options.displayName === 'script' || options.name === 'request') return + if (options.displayName === 'script' || options.name === 'request') { + return + } return log(options, ...args) } as typeof log diff --git a/apps/web/cypress/support/setupTests.ts b/apps/web/cypress/support/setupTests.ts index f459184eb8c..3951844cd28 100644 --- a/apps/web/cypress/support/setupTests.ts +++ b/apps/web/cypress/support/setupTests.ts @@ -20,7 +20,7 @@ beforeEach(() => { Cypress.env('amplitudeEventCache', []) // Mock analytics responses to avoid analytics in tests. - cy.intercept('https://interface.gateway.uniswap.org/v1/amplitude-proxy', (req) => { + cy.intercept('https://metrics.interface.gateway.uniswap.org/v1/amplitude-proxy', (req) => { const requestBody = JSON.stringify(req.body) const byteSize = new Blob([requestBody]).size req.alias = 'amplitude' diff --git a/apps/web/functions/utils/cache.ts b/apps/web/functions/utils/cache.ts index 5b3383604fe..a17c71b396c 100644 --- a/apps/web/functions/utils/cache.ts +++ b/apps/web/functions/utils/cache.ts @@ -31,9 +31,13 @@ class Cache { async match(request: string): Promise { const cache = await caches.open(CACHE_NAME) const response = await cache.match(request) - if (!response) return undefined + if (!response) { + return undefined + } const data: Data = JSON.parse(await response.text()) - if (!data.title || !data.image || !data.url) return undefined + if (!data.title || !data.image || !data.url) { + return undefined + } return data } diff --git a/apps/web/i18next-parser.config.js b/apps/web/i18next-parser.config.js index fe0620fed53..8b39cf8a4c3 100644 --- a/apps/web/i18next-parser.config.js +++ b/apps/web/i18next-parser.config.js @@ -22,7 +22,7 @@ module.exports = { keepRemoved: false, // Key separator used in your translation keys - keySeparator: '~~', + keySeparator: false, // see below for more details lexers: { diff --git a/apps/web/package.json b/apps/web/package.json index 42994da3b38..6aa805169ac 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -15,7 +15,6 @@ "i18n:upload": "./scripts/crowdin.sh upload", "i18n:download": "./scripts/crowdin.sh download", "i18n:download:if-missing": "ONLY_IF_MISSING=1 ./scripts/crowdin.sh download", - "i18n:extract": "i18next && node ./scripts/fix-empty-i18n-values.js", "start": "craco start", "start:cloud": "NODE_OPTIONS=--dns-result-order=ipv4first PORT=3001 REACT_APP_SKIP_CSP=1 npx wrangler pages dev --compatibility-flags=nodejs_compat --compatibility-date=2023-08-01 --proxy=3001 --port=3000 -- yarn start", "build:production": "yarn i18n:download:if-missing && craco build", @@ -131,7 +130,6 @@ "eslint-plugin-rulesdir": "0.2.2", "hardhat": "2.14.0", "husky": "^8.0.3", - "i18next-parser": "8.6.0", "jest": "29.7.0", "jest-extended": "4.0.1", "jest-fail-on-console": "3.1.1", @@ -162,6 +160,7 @@ "yarn-deduplicate": "6.0.0" }, "dependencies": { + "@amplitude/analytics-browser": "1.12.1", "@apollo/client": "3.9.6", "@graphql-codegen/cli": "^3.3.1", "@graphql-codegen/client-preset": "^3.0.1", diff --git a/apps/web/public/nfts-sitemap.xml b/apps/web/public/nfts-sitemap.xml index 5e72adbbb2f..2dbd9279fa9 100644 --- a/apps/web/public/nfts-sitemap.xml +++ b/apps/web/public/nfts-sitemap.xml @@ -2,632 +2,657 @@ https://app.uniswap.org/nfts/collection/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x60e4d786628fea6478f785a6d7e704777c86a7c6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c544 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x34d85c9cdeb23fa97cb08333b511ac86e1c4e258 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x99a9b7c1116f9ceeb1652de04d5969cce509b069 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xb7f7f6c52f2e2fdb1963eab30438024864c313f6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x23581767a106ae21c074b2276d25e5c3e136a68b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x8a90cab2b38dba80c64b7734e58ee1db38b8992e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xba30e5f9bb24caa003e9f2f0497ad287fdf95623 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xbd3531da5cf5857e7cfaa92426877b022e612cf8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x7bd29408f11d2bfc23c34f18275bbf23bb716bc7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x306b1ea3ecdf94ab739f1910bbda052ed4a9f949 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x1a92f7381b9f03921564a437210bb9396471050c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x5cc5b05a8a13e3fbdb0bb9fccd98d38e50f90c38 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x5af0d9827e0c53e4799bb226655a1de152a425a5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x3bf2922f4520a8ba0c2efc3d2a1539678dad5e9d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xe785e82358879f061bc3dcac6f0444462d4b5330 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x76be3b62873462d2142405439777e971754e8e77 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xfd43af6d3fe1b916c026f6ac35b3ede068d1ca01 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x1cb1a5e65610aeff2551a50f76a87a7d3fb649c6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x6339e5e072086621540d0362c4e3cea0d643e114 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xb932a70a57673d89f4acffbe830e8ed7f75fb9e0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x79fcdef22feed20eddacbb2587640e45491b757f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xa3aee8bce55beea1951ef834b99f3ac60d1abeeb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x769272677fab02575e84945f03eca517acc544cc - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x4db1f25d3d98600140dfc18deb7515be5bd293af - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x34eebee6942d8def3c125458d1a86e0a897fd6f9 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x59468516a8259058bad1ca5f8f4bff190d30e066 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x394e3d3044fc89fcdd966d3cb35ac0b32b0cda91 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x60bb1e2aa1c9acafb4d34f71585d7e959f387769 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x28472a58a490c5e09a238847f66a68a47cc76f0f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x341a1c534248966c4b6afad165b98daed4b964ef - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x82c7a8f707110f5fbb16184a5933e9f78a34c6ab - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xccc441ac31f02cd96c153db6fd5fe0a2f4e6a68d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x764aeebcf425d56800ef2c84f2578689415a2daa - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x160c404b2b49cbc3240055ceaee026df1e8497a0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xd2f668a8461d6761115daf8aeb3cdf5f40c532c6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x39ee2c7b3cb80254225884ca001f57118c8f21b6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xd774557b647330c91bf44cfeab205095f7e6c367 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x1792a96e5668ad7c167ab804a100ce42395ce54d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x04afa589e2b933f9463c5639f412b183ec062505 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xe75512aa3bec8f00434bbd6ad8b0a3fbff100ad6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x348fc118bcc65a92dc033a951af153d14d945312 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x892848074ddea461a15f337250da3ce55580ca85 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x5946aeaab44e65eb370ffaa6a7ef2218cff9b47d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x4b15a9c28034dc83db40cd810001427d3bd7163d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x7ea3cca10668b8346aec0bf1844a49e995527c8b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xb852c6b5892256c264cc2c888ea462189154d8d7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x9378368ba6b85c1fba5b131b530f5f5bedf21a18 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x2acab3dea77832c09420663b0e1cb386031ba17b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x0c2e57efddba8c768147d1fdf9176a0a6ebd5d83 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x08d7c0242953446436f34b4c78fe9da38c73668d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x8943c7bac1914c9a7aba750bf2b6b09fd21037e0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x364c828ee171616a39897688a831c2499ad972ec - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x7f36182dee28c45de6072a34d29855bae76dbe2f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xf61f24c2d93bf2de187546b14425bf631f28d6dc - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x797a48c46be32aafcedcfd3d8992493d8a1f256b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x123b30e25973fecd8354dd5f41cc45a3065ef88c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x6632a9d63e142f17a668064d41a21193b49b41a0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xf4ee95274741437636e748ddac70818b4ed7d043 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x57a204aa1042f6e66dd7730813f4024114d74f37 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xd1258db6ac08eb0e625b75b371c023da478e94a9 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x75e95ba5997eb235f40ecf8347cdb11f18ff640b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xd532b88607b1877fe20c181cba2550e3bbd6b31c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xa1d4657e0e6507d5a94d06da93e94dc7c8c44b51 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xedb61f74b0d09b2558f1eeb79b247c1f363ae452 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x7d8820fa92eb1584636f4f5b8515b5476b75171a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x231d3559aa848bf10366fb9868590f01d34bf240 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xad9fd7cb4fc7a0fbce08d64068f60cbde22ed34c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x0e9d6552b85be180d941f1ca73ae3e318d2d4f1f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xb716600ed99b4710152582a124c697a7fe78adbf - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xaadc2d4261199ce24a4b0a57370c4fcf43bb60aa - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x4e1f41613c9084fdb9e34e11fae9412427480e56 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x79986af15539de2db9a5086382daeda917a9cf0c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xc99c679c50033bbc5321eb88752e89a93e9e83c5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xc36cf0cfcb5d905b8b513860db0cfe63f6cf9f5c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x9c8ff314c9bc7f6e59a9d9225fb22946427edc03 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x3110ef5f612208724ca51f5761a69081809f03b7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x036721e5a769cc48b3189efbb9cce4471e8a48b1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x524cab2ec69124574082676e6f654a18df49a048 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x7ab2352b1d2e185560494d5e577f9d3c238b78c5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x32973908faee0bf825a343000fe412ebe56f802a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x7daec605e9e2a1717326eedfd660601e2753a057 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xc1caf0c19a8ac28c41fe59ba6c754e4b9bd54de9 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x33fd426905f149f8376e227d0c9d3340aad17af1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x466cfcd0525189b573e794f554b8a751279213ac - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x6be69b2a9b153737887cfcdca7781ed1511c7e36 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x80336ad7a747236ef41f47ed2c7641828a480baa - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x9401518f4ebba857baa879d9f76e1cc8b31ed197 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x4b61413d4392c806e6d0ff5ee91e6073c21d6430 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xc3f733ca98e0dad0386979eb96fb1722a1a05e69 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x09233d553058c2f42ba751c87816a8e9fae7ef10 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x960b7a6bcd451c9968473f7bbfd9be826efd549a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x36d30b3b85255473d27dd0f7fd8f35e36a9d6f06 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x698fbaaca64944376e2cdc4cad86eaa91362cf54 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x497a9a79e82e6fc0ff10a16f6f75e6fcd5ae65a8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x41a322b28d0ff354040e2cbc676f0320d8c8850d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xa9c0a07a7cb84ad1f2ffab06de3e55aab7d523e8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x8821bee2ba0df28761afff119d66390d594cd280 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x8c6def540b83471664edc6d5cf75883986932674 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x8d9710f0e193d3f95c0723eaaf1a81030dc9116d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x86825dfca7a6224cfbd2da48e85df2fc3aa7c4b1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x629a673a8242c2ac4b7b8c5d8735fbeac21a6205 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x9a534628b4062e123ce7ee2222ec20b86e16ca8f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xc2c747e0f7004f9e8817db2ca4997657a7746928 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x73da73ef3a6982109c4d5bdb0db9dd3e3783f313 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xc92ceddfb8dd984a89fb494c376f9a48b999aafc - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x3248e8ba90facc4fdd3814518c14f8cc4d980e4b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x67d9417c9c3c250f61a83c7e8658dac487b56b09 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xb6a37b5d14d502c3ab0ae6f3a0e058bc9517786e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x86c10d10eca1fca9daf87a279abccabe0063f247 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x4b3406a41399c7fd2ba65cbc93697ad9e7ea61e5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xb0640e8b5f24bedc63c33d371923d68fde020303 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xd3d9ddd0cf0a5f0bfb8f7fceae075df687eaebab - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xa5c0bd78d1667c13bfb403e2a3336871396713c5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x4d7d2e237d64d1484660b55c0a4cc092fa5e6716 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0xfcb1315c4273954f74cb16d5b663dbf479eec62e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x66d1db16101502ed0ca428842c619ca7b62c8fef - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x128675d4fddbc4a0d3f8aa777d8ee0fb8b427c2f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.7 https://app.uniswap.org/nfts/collection/0x19b86299c21505cdf59ce63740b240a9c822b5e4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z + 0.7 + + + https://app.uniswap.org/nfts/collection/0xacf63e56fd08970b43401492a02f6f38b6635c91 + 2024-05-20T17:20:52.753Z + 0.7 + + + https://app.uniswap.org/nfts/collection/0x0bebad1ff25c623dff9605dad4a8f782d5da37df + 2024-05-20T17:20:52.753Z + 0.7 + + + https://app.uniswap.org/nfts/collection/0xdceaf1652a131f32a821468dc03a92df0edd86ea + 2024-05-20T17:20:52.753Z + 0.7 + + + https://app.uniswap.org/nfts/collection/0x273f7f8e6489682df756151f5525576e322d51a3 + 2024-05-24T23:13:47.908Z + 0.7 + + + https://app.uniswap.org/nfts/collection/0x77372a4cc66063575b05b44481f059be356964a4 + 2024-05-24T23:13:47.908Z 0.7 \ No newline at end of file diff --git a/apps/web/public/pools-sitemap.xml b/apps/web/public/pools-sitemap.xml index 2989ee4c8be..444e031d2fa 100644 --- a/apps/web/public/pools-sitemap.xml +++ b/apps/web/public/pools-sitemap.xml @@ -2,3542 +2,4572 @@ https://app.uniswap.org/explore/pools/ethereum/0xcbcdf9626bc03e24f779434178a73a0b4bad62ed - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x4e68ccd3e89f51c3074ca5072bbac773960dfa36 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x4585fe77225b41b697c938b018e2ac67ac5a20c0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xc63b0708e2f7e69cb8a1df0e1389a98c35a76d52 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x99ac8ca7087fa4a2a1fb6357269965a2014abc35 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x11b815efb8f581194ae79006d24e0d814b7697f6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xa6cc3c2531fdaa6ae1a3ca84c2855806728693e8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x5777d92f208679db4b9778590fa3cab3ac9e2168 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x1d42064fc4beb5f8aaf85f4617ae8b3b5b8bd801 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xc2e9f25be6257c210d7adf0d4cd6e3e881ba25f8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x11950d141ecb863f01007add7d1a342041227b58 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xc5c134a1f112efa96003f8559dba6fac0ba77692 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x109830a1aaad605bbf02a9dfa7b0b92ec2fb7daa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x1df4c6e36d61416813b42fe32724ef11e363eddc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x12d6867fa648d269835cf69b49f125147754b54d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x3416cf6c708da44db2624d63ea0aaef7113527c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xe8c6c9227491c0a8156a0106a0204d881bb7e531 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x04708077eca6bb527a5bbbd6358ffb043a9c1c14 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x9db9e0e53058c89e5b94e29621a205198648425b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xf239009a101b6b930a527deaab6961b6e7dec8a6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xfe0df74636bc25c7f2400f22fe7dae32d39443d2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xf4c5e0f4590b6679b3030d29a84857f226087fef - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x5764a6f2212d502bc5970f9f129ffcd61e5d7563 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xa3f558aebaecaf0e11ca4b2199cc5ed341edfd74 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x99132b53ab44694eeb372e87bced3929e4ab8456 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x6c6bc977e13df9b0de53b251522280bb72383700 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x9d96880952b4c80a55099b9c258250f2cc5813ec - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x3afdc5e6dfc0b0a507a8e023c9dce2cafc310316 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x290a6a7460b308ee3f19023d2d00de604bcf5b42 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xac4b3dacb91461209ae9d41ec517c2b9cb1b7daf - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x60594a405d53811d3bc4766596efd80fd545a270 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x331399c614ca67dee86733e5a2fba40dbb16827c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x4b5ab61593a2401b1075b90c04cbcdd3f87ce011 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x844eb5c280f38c7462316aad3f338ef9bda62668 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xe936f0073549ad8b1fa53583600d629ba9375161 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x2f62f2b4c5fcd7570a709dec05d68ea19c82a9ec - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x381fe4eb128db1621647ca00965da3f9e09f4fac - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x97e7d56a0408570ba1a7852de36350f7713906ec - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xcd423f3ab39a11ff1d9208b7d37df56e902c932b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xe15e6583425700993bd08f51bf6e7b73cd5da91b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x69d91b94f0aaf8e8a2586909fa77a5c2c89818d5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xe42318ea3b998e8355a3da364eb9d48ec725eb45 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xad9ef19e289dcbc9ab27b83d2df53cdeff60f02d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x3b685307c8611afb2a9e83ebc8743dc20480716e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x7bea39867e4169dbe237d55c8242a8f2fcdcc387 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x7b1e5d984a43ee732de195628d20d05cfabc3cc7 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x7858e59e0c01ea06df3af3d20ac7b0003275d4bf - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xae2a25cbdb19d0dc0dddd1d2f6b08a6e48c4a9a9 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x21b8065d10f73ee2e260e5b47d3344d3ced7596e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x517f9dd285e75b599234f7221227339478d0fcc8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xa43fe16908251ee70ef74718545e4fe6c5ccec9f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x0af81cd5d9c124b4859d65697a4cd10ee223746a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xca7c2771d248dcbe09eabe0ce57a62e18da178c0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x09d1d767edf8fa23a64c51fa559e0688e526812f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x7b73644935b8e68019ac6356c40661e1bc315860 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x180efc1349a69390ade25667487a826164c9c6e4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x9c4fe5ffd9a9fc5678cfbd93aa2d4fd684b67c4c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xa478c2975ab1ea89e8196811f51a7b7ade33eb11 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xbb2b8038a1640196fbe3e38816f3e67cba72d940 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x9ec9367b8c4dd45ec8e7b800b1f719251053ad60 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xc91ef786fbf6d62858262c82c63de45085dea659 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x197d7010147df7b99e9025c724f13723b29313f8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x25647e01bd0967c1b9599fa3521939871d1d0888 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x2f0b1417aa42ebf0b4ca1154212847f6094d708d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x6ada49aeccf6e556bb7a35ef0119cc8ca795294a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x2a6c340bcbb0a79d3deecd3bc5cbc2605ea9259f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xda2d09fbbf8ee4b5051a0e9b562c5fcb4b393b18 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x48d20b3e529fb3dd7d91293f80638df582ab2daa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x4028daac072e492d34a3afdbef0ba7e35d8b55c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xc2eab7d33d3cb97692ecb231a5d0e4a649cb539d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xc5be99a02c6857f9eac67bbce58df5572498f40c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xe4b8583ccb95b25737c016ac88e539d0605949e8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x8dbee21e8586ee356130074aaa789c33159921ca - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x43de4318b6eb91a7cf37975dbb574396a7b5b5c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x9ff68f61ca5eb0c6606dc517a9d44001e564bb66 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xa29fe6ef9592b5d408cca961d0fb9b1faf497d6d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x1b1137dd16faa651e38a9dfb5d9ffff7767fdf62 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x470e8de2ebaef52014a47cb5e6af86884947f08c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x8fb8e9921922d2ffb529a95d28a0d06d275d7a59 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xd3d2e2692501a5c9ca623199d38826e513033a17 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x97e1fcb93ae7267dbafad23f7b9afaa08264cfd8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xa5e9c917b4b821e4e0a5bbefce078ab6540d6b5e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x2cc846fff0b08fb3bffad71f53a60b4b6e6d6482 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x959873fb4fc11825fba83c80c4c632db1e936e15 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xa7480aafa8ad2af3ce24ac6853f960ae6ac7f0c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xc7e6b676bfc73ae40bcc4577f22aab1682c691c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x570febdf89c07f256c75686caca215289bb11cfc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x343fd171caf4f0287ae6b87d75a8964dc44516ab - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xcaa004418eb42cdf00cb057b7c9e28f0ffd840a5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xe3d3551bb608e7665472180a20280630d9e938aa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xb6b0c651c37ec4ca81c0a128420e02001a57fac2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x4e34da137f0b317c633838458e0c923a5e088752 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0xfe9e7931e55c514c33d489c88582fa36e84bd8e3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x5281e311734869c64ca60ef047fd87759397efe6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x149148acc3b06b8cc73af3a10e84189243a35925 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x8ef79d6c328c25da633559c20c75f638a4863462 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x14af1804dbbf7d621ecc2901eef292a24a0260ea - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x80a9ae39310abf666a87c743d6ebbd0e8c42158e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc31e54c7a869b9fcbecc14363cf510d1c41fa443 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x2f5e87c9312fa29aed5c179e456625d79015299c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc6962004f452be9203591991d15f6b388e09e8d0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc6f780497a95e246eb9449f5e4770916dcd6396a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x641c00a822e8b671738d32a431a4fb6074e5c79d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x92c63d0e701caae670c9415d91c474f686298f00 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x1aeedd3727a6431b8f070c0afaa81cc74f273882 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xcda53b1f66614552f834ceef361a8d12a0b8dad8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x35218a1cbac5bbc3e57fd9bd38219d37571b3537 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x17c14d2c404d167802b16c450d3c99f88f2c4f4d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x468b88941e7cc0b88c1869d68ab6b570bcef62ff - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xdbaeb7f0dfe3a0aafd798ccecb5b22e708f7852c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x149e36e72726e0bcea5c59d40df2c43f60f5a22d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xbaaf1fc002e31cb12b99e4119e5e350911ec575b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xa67f72f21bd9f91db2da2d260590da5e6c437009 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x92fd143a8fa0c84e016c2765648b9733b0aa519e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x7cf803e8d82a50504180f417b8bc7a493c0a0503 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x81c48d31365e6b526f6bbadc5c9aafd822134863 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x446bf9748b4ea044dd759d9b9311c70491df8f29 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc82819f72a9e77e2c0c3a69b3196478f44303cf4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x50c7390dfdd3756139e6efb5a461c2eb7331ceb4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x1dfc1054e0e2a10e33c9ca21aad5aa8a1cce91e3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc91b7b39bbb2c733f0e7459348fd0c80259c8471 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x59d72ddb29da32847a4665d08ffc8464a7185fae - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x09ba302a3f5ad2bf8853266e271b005a5b3716fe - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xa77d77c9773c35e910acc2e30cefe52b54a58414 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x8da66e470403b3d3eee66c67e2c61fda6e248ad1 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x2f020e708811c054f146eebcc4d5a215fd4eec26 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x7e7fb3cceca5f2ac952edf221fd2a9f62e411980 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x68c685fd52a56f04665b491d491355a624540e85 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xa8328bf492ba1b77ad6381b3f7567d942b000baf - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc0cf0f380ddb44dbcaf19a86d094c8bba3efa04a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xa169d1ab5c948555954d38700a6cdaa7a4e0c3a0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x1862200e8e7ce1c0827b792d0f9546156f44f892 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x05bbaaa020ff6bea107a9a1e06d2feb7bfd79ed2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xd02a4969dc12bb889754361f8bcf3385ac1b2077 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc24f7d8e51a64dc1238880bd00bb961d54cbeb29 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x7c06736e41236fecd681dd3353aa77ecd19ea565 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc473e2aee3441bf9240be85eb122abb059a3b57c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x14353445c8329df76e6f15e9ead18fa2d45a8bb6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x2039f8c9cd32ba9cd2ea7e575d5b1abea93f7527 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xd3e11119d2680c963f1cdcffece0c4ade823fb58 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x8e295789c9465487074a65b1ae9ce0351172393f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x97bca422ec0ee4851f2110ea743c1cd0a14835a1 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xbe3ad6a5669dc0b8b12febc03608860c31e2eef6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x56ebd63a756b94d3de9cea194896b4920b64fb01 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xe2ddd33585b441b9245085588169f35108f85a6e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x84436a2af97f37018db116ae8e1b691666db3d00 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x21b8065d10f73ee2e260e5b47d3344d3ced7596e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x517f9dd285e75b599234f7221227339478d0fcc8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xa43fe16908251ee70ef74718545e4fe6c5ccec9f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x0af81cd5d9c124b4859d65697a4cd10ee223746a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xca7c2771d248dcbe09eabe0ce57a62e18da178c0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x09d1d767edf8fa23a64c51fa559e0688e526812f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x7b73644935b8e68019ac6356c40661e1bc315860 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x180efc1349a69390ade25667487a826164c9c6e4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x9c4fe5ffd9a9fc5678cfbd93aa2d4fd684b67c4c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xa478c2975ab1ea89e8196811f51a7b7ade33eb11 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xbb2b8038a1640196fbe3e38816f3e67cba72d940 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x9ec9367b8c4dd45ec8e7b800b1f719251053ad60 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc91ef786fbf6d62858262c82c63de45085dea659 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x197d7010147df7b99e9025c724f13723b29313f8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x25647e01bd0967c1b9599fa3521939871d1d0888 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x2f0b1417aa42ebf0b4ca1154212847f6094d708d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x6ada49aeccf6e556bb7a35ef0119cc8ca795294a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x2a6c340bcbb0a79d3deecd3bc5cbc2605ea9259f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xda2d09fbbf8ee4b5051a0e9b562c5fcb4b393b18 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x48d20b3e529fb3dd7d91293f80638df582ab2daa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x4028daac072e492d34a3afdbef0ba7e35d8b55c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc2eab7d33d3cb97692ecb231a5d0e4a649cb539d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc5be99a02c6857f9eac67bbce58df5572498f40c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xe4b8583ccb95b25737c016ac88e539d0605949e8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x8dbee21e8586ee356130074aaa789c33159921ca - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x43de4318b6eb91a7cf37975dbb574396a7b5b5c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x9ff68f61ca5eb0c6606dc517a9d44001e564bb66 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xa29fe6ef9592b5d408cca961d0fb9b1faf497d6d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x1b1137dd16faa651e38a9dfb5d9ffff7767fdf62 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x470e8de2ebaef52014a47cb5e6af86884947f08c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x8fb8e9921922d2ffb529a95d28a0d06d275d7a59 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xd3d2e2692501a5c9ca623199d38826e513033a17 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x97e1fcb93ae7267dbafad23f7b9afaa08264cfd8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xa5e9c917b4b821e4e0a5bbefce078ab6540d6b5e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x2cc846fff0b08fb3bffad71f53a60b4b6e6d6482 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x959873fb4fc11825fba83c80c4c632db1e936e15 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xa7480aafa8ad2af3ce24ac6853f960ae6ac7f0c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xc7e6b676bfc73ae40bcc4577f22aab1682c691c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x570febdf89c07f256c75686caca215289bb11cfc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x343fd171caf4f0287ae6b87d75a8964dc44516ab - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xcaa004418eb42cdf00cb057b7c9e28f0ffd840a5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xe3d3551bb608e7665472180a20280630d9e938aa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xb6b0c651c37ec4ca81c0a128420e02001a57fac2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x4e34da137f0b317c633838458e0c923a5e088752 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0xfe9e7931e55c514c33d489c88582fa36e84bd8e3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x5281e311734869c64ca60ef047fd87759397efe6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x149148acc3b06b8cc73af3a10e84189243a35925 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x8ef79d6c328c25da633559c20c75f638a4863462 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x68f5c0a2de713a54991e01858fd27a3832401849 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x4533bad2dc588f0fadf8d2e72386d4cd6a19b519 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x85149247691df622eaf1a8bd0cafd40bc45154a9 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x0392b358ce4547601befa962680bede836606ae2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x1c3140ab59d6caf9fa7459c6f83d4b52ba881d36 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xd1f1bad4c9e6c44dec1e9bf3b94902205c5cd6c3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x03af20bdaaffb4cc0a521796a223f7d85e2aac31 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x73b14a78a0d396c521f954532d43fd5ffe385216 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xac85eaf55e9c60ed40a683de7e549d23fdfbeb33 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x04f6c85a1b00f6d9b75f91fd23835974cc07e65c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x730691cdac3cbd4d41fc5eb9d8abbb0cea795b94 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x535541f1aa08416e69dc4d610131099fa2ae7222 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xfc1f3296458f9b2a27a0b91dd7681c4020e09d05 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x85c31ffa3706d1cce9d525a00f1c7d4a2911754c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xd52533a3309b393afebe3176620e8ccfb6159f8a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xff7fbdf7832ae524deda39ca402e03d92adff7a5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xb589969d38ce76d3d7aa319de7133bc9755fd840 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xf334f6104a179207ddacfb41fa3567feea8595c2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x1fb3cf6e48f1e7b10213e7b6d87d4c073c7fdb7b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xd4344ea0c5ade7e22b9b275f0bde7a145dec5a23 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x5b42a63d6741416ce9a7b9f4f16d8c9231ccddd4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x252cbdff917169775be2b552ec9f6781af95e7f6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x2ab22ac86b25bd448a4d9dc041bd2384655299c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xc858a329bf053be78d6239c4a4343b8fbd21472b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xa73c628eaf6e283e26a7b1f8001cf186aa4c0e8e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xb533c12fb4e7b53b5524eab9b47d93ff6c7a456f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x2ae3d6096d8215ac2acddf30c60caa984ea5debe - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x19ea026886cbb7a900ecb2458636d72b5cae223b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x6f32061f59a21086c334d0d45f804089ce374aaf - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xfaf037caafa9620bfaebc04c298bf4a104963613 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xadb35413ec50e0afe41039eac8b930d313e94fa4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xe9e3893921de87b1194a8108f9d70c24bde71c27 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xf1f199342687a7d78bcc16fce79fa2665ef870e1 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xf44acaa38be5e965c5ddf374e7a2ba270e580684 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x36e42931a765022790b797963e42c5522d6b585a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x5adba6c5589c50791dd65131df29677595c7efa7 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x3249e3e3e4133ee18e65347daf586610cc265f54 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xca1b837c87c6563910c2befa48834fa2a8c3d72d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x6ef7b14bcd8d989cef8f8ec8ba4bf371b2ac95fd - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x37ffd11972128fd624337ebceb167c8c0a5115ff - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xe62bd99a9501ca33d98913105fc2bec5bae6e5dd - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xb2ac2e5a3684411254d58b1c5a542212b782114d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xb0efaf46a1de55c54f333f93b1f0641e73bc16d0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xd0fa3b5264ccde31e8b094b86bca4a1e97d3c603 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xad4c666fc170b468b19988959eb931a3676f0e9f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x790fde1fd6d2568050061a88c375d5c2e06b140b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xaefc1edaede6adadcdf3bb344577d45a80b19582 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xa8a5356ee5d02fe33d72355e4f698782f8f199e8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x55bc964fe3b0c8cc2d4c63d65f1be7aef9bb1a3c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x95d9d28606ee55de7667f0f176ebfc3215cfd9c0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x21b8065d10f73ee2e260e5b47d3344d3ced7596e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x517f9dd285e75b599234f7221227339478d0fcc8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xa43fe16908251ee70ef74718545e4fe6c5ccec9f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x0af81cd5d9c124b4859d65697a4cd10ee223746a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xca7c2771d248dcbe09eabe0ce57a62e18da178c0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x09d1d767edf8fa23a64c51fa559e0688e526812f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x7b73644935b8e68019ac6356c40661e1bc315860 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x180efc1349a69390ade25667487a826164c9c6e4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x9c4fe5ffd9a9fc5678cfbd93aa2d4fd684b67c4c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xa478c2975ab1ea89e8196811f51a7b7ade33eb11 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xbb2b8038a1640196fbe3e38816f3e67cba72d940 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x9ec9367b8c4dd45ec8e7b800b1f719251053ad60 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xc91ef786fbf6d62858262c82c63de45085dea659 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x197d7010147df7b99e9025c724f13723b29313f8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x25647e01bd0967c1b9599fa3521939871d1d0888 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x2f0b1417aa42ebf0b4ca1154212847f6094d708d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x6ada49aeccf6e556bb7a35ef0119cc8ca795294a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x2a6c340bcbb0a79d3deecd3bc5cbc2605ea9259f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xda2d09fbbf8ee4b5051a0e9b562c5fcb4b393b18 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x48d20b3e529fb3dd7d91293f80638df582ab2daa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x4028daac072e492d34a3afdbef0ba7e35d8b55c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xc2eab7d33d3cb97692ecb231a5d0e4a649cb539d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xc5be99a02c6857f9eac67bbce58df5572498f40c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xe4b8583ccb95b25737c016ac88e539d0605949e8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x8dbee21e8586ee356130074aaa789c33159921ca - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x43de4318b6eb91a7cf37975dbb574396a7b5b5c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x9ff68f61ca5eb0c6606dc517a9d44001e564bb66 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xa29fe6ef9592b5d408cca961d0fb9b1faf497d6d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x1b1137dd16faa651e38a9dfb5d9ffff7767fdf62 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x470e8de2ebaef52014a47cb5e6af86884947f08c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x8fb8e9921922d2ffb529a95d28a0d06d275d7a59 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xd3d2e2692501a5c9ca623199d38826e513033a17 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x97e1fcb93ae7267dbafad23f7b9afaa08264cfd8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xa5e9c917b4b821e4e0a5bbefce078ab6540d6b5e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x2cc846fff0b08fb3bffad71f53a60b4b6e6d6482 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x959873fb4fc11825fba83c80c4c632db1e936e15 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xa7480aafa8ad2af3ce24ac6853f960ae6ac7f0c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xc7e6b676bfc73ae40bcc4577f22aab1682c691c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x570febdf89c07f256c75686caca215289bb11cfc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x343fd171caf4f0287ae6b87d75a8964dc44516ab - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xcaa004418eb42cdf00cb057b7c9e28f0ffd840a5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xe3d3551bb608e7665472180a20280630d9e938aa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xb6b0c651c37ec4ca81c0a128420e02001a57fac2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x4e34da137f0b317c633838458e0c923a5e088752 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xfe9e7931e55c514c33d489c88582fa36e84bd8e3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x5281e311734869c64ca60ef047fd87759397efe6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x149148acc3b06b8cc73af3a10e84189243a35925 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x8ef79d6c328c25da633559c20c75f638a4863462 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x45dda9cb7c25131df268515131f647d726f50608 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x50eaedb835021e4a108b7290636d62e9765cc6d7 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x167384319b41f7094e62f7506409eb38079abff8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xa374094527e1673a86de625aa59517c5de346d32 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x86f1d8390222a3691c28938ec7404a1661e618e0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xeda1094f59a4781456734e5d258b95e6be20b983 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x847b64f9d3a95e977d157866447a5c0a5dfa0ee5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x94ab9e4553ffb839431e37cc79ba8905f45bfbea - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x0e44ceb592acfc5d3f09d996302eb4c499ff8c10 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x1e5bd2ab4c308396c06c182e1b7e7ba8b2935b83 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x9b08288c3be4f62bbf8d1c20ac9c5e6f9467d8b7 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xb6e57ed85c4c9dbfef2a68711e9d6f36c56e0fcb - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x3e31ab7f37c048fc6574189135d108df80f0ea26 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xd36ec33c8bed5a9f7b6630855f1533455b98a418 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xdac8a8e6dbf8c690ec6815e0ff03491b2770255d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xfe343675878100b344802a6763fd373fdeed07a4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x0a28c2f5e0e8463e047c203f00f649812ae67e4f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x88f3c15523544835ff6c738ddb30995339ad57d6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x98b9162161164de1ed182a0dfa08f5fbf0f733ca - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xeef1a9507b3d505f0062f2be9453981255b503c8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xc4c06c9a239f94fc0a1d3e04d23c159ebe8316f1 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x849ec65748107aedc518dbc42961f358ea1361a7 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x2db87c4831b2fec2e35591221455834193b50d1b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xa4d8c89f0c20efbe54cba9e7e7a7e509056228d9 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x642f28a89fa9d0fa30e664f71804bfdd7341d21f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x2aceda63b5e958c45bd27d916ba701bc1dc08f7a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x781067ef296e5c4a4203f81c593274824b7c185d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x4ccd010148379ea531d6c587cfdd60180196f9b1 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xd866fac7db79994d08c0ca2221fee08935595b4b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x941061770214613ba0ca3db9a700c39587bb89b6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xa9077cdb3d13f45b8b9d87c43e11bce0e73d8631 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xa01f64fa1b923dd9c5c7618b39a6ba8098a88863 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xa830ff28bb7a46570a7e43dc24a35a663b9cfc2e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x8837a61644d523cbe5216dde226f8f85e3aa9be3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xca5d44977d6de1846530eb434167b208752fba7d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x4d05f2a005e6f36633778416764e82d1d12e7fbb - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x41e64a5bc929fa8e6a9c8d7e3b81a13b21ff3045 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x3ea34cfc9322273311f7843826a2581c4a00fd39 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x785061ed819414dc4269d2a5d5974069c0daea96 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x3f5228d0e7d75467366be7de2c31d0d098ba2c23 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x2e3f22e9a1c2470b2e293351f48c99e1fd788f32 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x2a08c38c7e1fa969325e2b64047abb085dec3756 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xe6c36eed27c2e8ecb9a233bf12da06c9730b5955 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xefa98fdf168f372e5e9e9b910fcdfd65856f3986 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x76fa081e510f43ac8335efdb4db88c9ff1894413 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xc6832ef0af793336aa44a936e54b992bff47e7cd - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x865f456479a21e2b3d866561d7171a3d0a7b112d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xbd934a7778771a7e2d9bf80596002a214d8c9304 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x9ab9f658104467604b5afa9a3e1df62f35f7b208 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x6e430d59ba145c59b73a6db674fe3d53c1f31cae - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x21b8065d10f73ee2e260e5b47d3344d3ced7596e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x517f9dd285e75b599234f7221227339478d0fcc8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xa43fe16908251ee70ef74718545e4fe6c5ccec9f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x0af81cd5d9c124b4859d65697a4cd10ee223746a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xca7c2771d248dcbe09eabe0ce57a62e18da178c0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x09d1d767edf8fa23a64c51fa559e0688e526812f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x7b73644935b8e68019ac6356c40661e1bc315860 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x180efc1349a69390ade25667487a826164c9c6e4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x9c4fe5ffd9a9fc5678cfbd93aa2d4fd684b67c4c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xa478c2975ab1ea89e8196811f51a7b7ade33eb11 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xbb2b8038a1640196fbe3e38816f3e67cba72d940 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x9ec9367b8c4dd45ec8e7b800b1f719251053ad60 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xc91ef786fbf6d62858262c82c63de45085dea659 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x197d7010147df7b99e9025c724f13723b29313f8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x25647e01bd0967c1b9599fa3521939871d1d0888 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x2f0b1417aa42ebf0b4ca1154212847f6094d708d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x6ada49aeccf6e556bb7a35ef0119cc8ca795294a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x2a6c340bcbb0a79d3deecd3bc5cbc2605ea9259f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xda2d09fbbf8ee4b5051a0e9b562c5fcb4b393b18 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x48d20b3e529fb3dd7d91293f80638df582ab2daa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x4028daac072e492d34a3afdbef0ba7e35d8b55c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xc2eab7d33d3cb97692ecb231a5d0e4a649cb539d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xc5be99a02c6857f9eac67bbce58df5572498f40c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xe4b8583ccb95b25737c016ac88e539d0605949e8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x8dbee21e8586ee356130074aaa789c33159921ca - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x43de4318b6eb91a7cf37975dbb574396a7b5b5c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x9ff68f61ca5eb0c6606dc517a9d44001e564bb66 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xa29fe6ef9592b5d408cca961d0fb9b1faf497d6d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x1b1137dd16faa651e38a9dfb5d9ffff7767fdf62 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x470e8de2ebaef52014a47cb5e6af86884947f08c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x8fb8e9921922d2ffb529a95d28a0d06d275d7a59 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xd3d2e2692501a5c9ca623199d38826e513033a17 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x97e1fcb93ae7267dbafad23f7b9afaa08264cfd8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xa5e9c917b4b821e4e0a5bbefce078ab6540d6b5e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x2cc846fff0b08fb3bffad71f53a60b4b6e6d6482 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x959873fb4fc11825fba83c80c4c632db1e936e15 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xa7480aafa8ad2af3ce24ac6853f960ae6ac7f0c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xc7e6b676bfc73ae40bcc4577f22aab1682c691c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x570febdf89c07f256c75686caca215289bb11cfc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x343fd171caf4f0287ae6b87d75a8964dc44516ab - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xcaa004418eb42cdf00cb057b7c9e28f0ffd840a5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xe3d3551bb608e7665472180a20280630d9e938aa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xb6b0c651c37ec4ca81c0a128420e02001a57fac2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x4e34da137f0b317c633838458e0c923a5e088752 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0xfe9e7931e55c514c33d489c88582fa36e84bd8e3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x5281e311734869c64ca60ef047fd87759397efe6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x149148acc3b06b8cc73af3a10e84189243a35925 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x8ef79d6c328c25da633559c20c75f638a4863462 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x9e37cb775a047ae99fc5a24dded834127c4180cd - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x48413707b70355597404018e7c603b261fcadf3f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xade9bcd4b968ee26bed102dd43a55f6a8c2416df - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xda679706ff21114ac9fac5198bff24543f357a16 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xba3f945812a83471d709bce9c3ca699a19fb46f7 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xc9034c3e7f58003e6ae0c8438e7c8f4598d5acaa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x4c36388be6f416a29c8d8eee81c771ce6be14b18 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xa1b2457c0b627f97f6cc892946a382451e979014 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x4b0aaf3ebb163dd45f663b38b6d93f6093ebc2d3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xae2ce200bdb67c472030b31f602f0756c9aeb61c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x3bc5180d5439b500f381f9a46f15dd6608101671 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x5122e02898ece3bc62df8c1efdb29a9e914244d3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x24e1cbd6fed006ceed9af0dce688acc7951d57a9 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x2556230ac694093d4d3b7b965a2f2d77d4c403a4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xdaca082c2c7d052a96fa83ea9d3a7b6839e39586 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xa555149210075702a734968f338d5e1cbd509354 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x10648ba41b8565907cfa1496765fa4d95390aa0d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x00bcec1526dae1e170a53017b8775a93b7810d7c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x20e068d76f9e90b90604500b84c7e19dcb923e7e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x6b93950a9b589bc32b82a5df4e5148f98a7fae27 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xd9caa6dbe6791fcb7fc9fb59d1a6b3dd8c1c2339 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x62e81e93136ac42a1ada48d4098f5f9e703e7455 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x84206d33845c9d811438b6fe4e7a0c634748dc50 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xd0b53d9277642d899df5c87a3966a349a798f224 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xcfa7c4bb565915f1c4f9475e2a0536d31efad776 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xa7de21f28ca460b45373b217cd4eb111c3faeff8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xb64dff20dd5c47e6dbb56ead80d23568006dec1e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xad4e969f4193878e5cc89cefb57faf6c7c0048da - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xdf5eb97e3e23ca7f5a5fd2264680377c211310ba - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xf16baaae8eb7b37f4280e72924479f69e7a61f32 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xe745a591970e0fa981204cf525e170a2b9e4fb93 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x64b74c66b9ba60ca668b781289767ae7298f37ae - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x17e1ebd791e7253a5e606fd94c5b66c14d873136 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x46715bd57b9ec01deadb35fe096fb44acda79414 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x3447accd4b8e735329d1065244aad2ed630f0122 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x2feb7f3ffc243f7de94d5ea5975533d301584e07 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x0d5959a52e7004b601f0be70618d01ac3cdce976 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x2170ca774e48a3f51559917ada6f9d7ae8f7bfea - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x62a76dfa8951aefcff787e790782db3633ebf422 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x8073679e0b3b2d1d665777cf1b2b5b1c2d3d2d0c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x143f1a6f3fb32e6ab3f22d3cc6b417b5c2197599 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x82ad659c2f152aad59bb37cbc5e7663a2de0c607 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xa4efe9e8e2a2d5a2ac46805f233b8e49d0e11955 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xfcc89a1f250d76de198767d33e1ca9138a7fb54b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x2faa2b42b782d578a160f61bb7cd763a17476730 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xdd44c0e83c2570062d1e6fdd440b4724862e8f31 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xe3930a14641786e123e7bbe842d701fa1cbfe2df - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x6d03360ce4764e862ed81660c1f76cc2711b14b6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xc055f66f228105072315247785c00299d0ce27e8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xcae1d141ab11cef0a415cf0440025e1e5e962e06 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x21b8065d10f73ee2e260e5b47d3344d3ced7596e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x517f9dd285e75b599234f7221227339478d0fcc8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xa43fe16908251ee70ef74718545e4fe6c5ccec9f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x0af81cd5d9c124b4859d65697a4cd10ee223746a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xca7c2771d248dcbe09eabe0ce57a62e18da178c0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x09d1d767edf8fa23a64c51fa559e0688e526812f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x7b73644935b8e68019ac6356c40661e1bc315860 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x180efc1349a69390ade25667487a826164c9c6e4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x9c4fe5ffd9a9fc5678cfbd93aa2d4fd684b67c4c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xa478c2975ab1ea89e8196811f51a7b7ade33eb11 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xbb2b8038a1640196fbe3e38816f3e67cba72d940 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x9ec9367b8c4dd45ec8e7b800b1f719251053ad60 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xc91ef786fbf6d62858262c82c63de45085dea659 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x197d7010147df7b99e9025c724f13723b29313f8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x25647e01bd0967c1b9599fa3521939871d1d0888 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x2f0b1417aa42ebf0b4ca1154212847f6094d708d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x6ada49aeccf6e556bb7a35ef0119cc8ca795294a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x2a6c340bcbb0a79d3deecd3bc5cbc2605ea9259f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xda2d09fbbf8ee4b5051a0e9b562c5fcb4b393b18 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x48d20b3e529fb3dd7d91293f80638df582ab2daa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x4028daac072e492d34a3afdbef0ba7e35d8b55c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xc2eab7d33d3cb97692ecb231a5d0e4a649cb539d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xc5be99a02c6857f9eac67bbce58df5572498f40c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xe4b8583ccb95b25737c016ac88e539d0605949e8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x8dbee21e8586ee356130074aaa789c33159921ca - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x43de4318b6eb91a7cf37975dbb574396a7b5b5c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x9ff68f61ca5eb0c6606dc517a9d44001e564bb66 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xa29fe6ef9592b5d408cca961d0fb9b1faf497d6d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x1b1137dd16faa651e38a9dfb5d9ffff7767fdf62 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x470e8de2ebaef52014a47cb5e6af86884947f08c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x8fb8e9921922d2ffb529a95d28a0d06d275d7a59 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xd3d2e2692501a5c9ca623199d38826e513033a17 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x97e1fcb93ae7267dbafad23f7b9afaa08264cfd8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xa5e9c917b4b821e4e0a5bbefce078ab6540d6b5e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x2cc846fff0b08fb3bffad71f53a60b4b6e6d6482 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x959873fb4fc11825fba83c80c4c632db1e936e15 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xa7480aafa8ad2af3ce24ac6853f960ae6ac7f0c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xc7e6b676bfc73ae40bcc4577f22aab1682c691c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x570febdf89c07f256c75686caca215289bb11cfc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x343fd171caf4f0287ae6b87d75a8964dc44516ab - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xcaa004418eb42cdf00cb057b7c9e28f0ffd840a5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xe3d3551bb608e7665472180a20280630d9e938aa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xb6b0c651c37ec4ca81c0a128420e02001a57fac2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x4e34da137f0b317c633838458e0c923a5e088752 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0xfe9e7931e55c514c33d489c88582fa36e84bd8e3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x5281e311734869c64ca60ef047fd87759397efe6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x149148acc3b06b8cc73af3a10e84189243a35925 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x8ef79d6c328c25da633559c20c75f638a4863462 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x0f338ec12d3f7c3d77a4b9fcc1f95f3fb6ad0ea6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x4eaa90264d6a3567228dcb5cfc242200da586437 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x6fe9e9de56356f7edbfcbb29fab7cd69471a4869 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xf420603317a0996a3fce1b1a80993eaef6f7ae1a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x47a90a2d92a8367a91efa1906bfc8c1e05bf10c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x41bf5eeae051fbd2e97b76b5f8f0fdcc1a1e526b - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x28df0835942396b7a1b7ae1cd068728e6ddbbafd - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xa3f3664a52f01b42557524bd14556e379daf5669 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x1fd22fa7274bafebdfb1881321709f1219744829 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xe39cfc1a2e51a09ecbd060a24ee4eef5a97697bb - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x06396509195eb9e07c38a016694dc9ff535b128a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x5a1c486edefda2f09d3b349fadc38524f1743826 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x5bf1cf153c102a79d9e18b7fb7c79ba57fa70d0c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x2c3c320d49019d4f9a92352e947c7e5acfe47d68 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x4141325bac36affe9db165e854982230a14e6d48 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x17507bef4c3abc1bc715be723ee1baf571256e05 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x8149b92ea743cc382aada523b68b8834733b9015 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xc98f01bf2141e1140ef8f8cad99d4b021d10718f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x7f9d307973cdabe42769d9712df8ee1cc1a28d10 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x5c87da28a45e5089b762dcbbd86f743d14c54317 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x2cd97604ef77bbcb1fa0cff47545dff8ec7def08 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x7862d9b4be2156b15d54f41ee4ede2d5b0b455e4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x554548b404213c7efcdbab933f52edfe3c581834 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x63008c5ea4e47f5421e0e1428b1c5043a507d0d0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x0350ca994791c4b07a5b02b08aaf9d6fc8ab510e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x32776ed4d96ed069a2d812773f0ad8ad9ef83cf8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x84f3ca9b7a1579ff74059bd0e8929424d3fa330e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x5289a8dbf7029ee0b0498a84777ed3941d9acfec - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xb2bc284ab4c953b7f7a06d59c0ceb2de26405f22 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x508acf810857fefa86281499068ad5d19ebce325 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xccdfcd1aac447d5b29980f64b831c532a6a33726 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x4fb87838a29b37598099ef5aa6b3fbeeef987c50 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x515e94dc736b9d8b7d28ecf1cece0aba3d75da97 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xfd6e5b7c30538dff2752058e425ad01a56b831cc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xcb99fe720124129520f7a09ca3cbef78d58ed934 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xd2f21358c1549be193537b2a4c5dc7f0228ae011 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x93094ed1c907e4bca7eb041cb659da94f7e1b58e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xd37e6ecb991d1a0e7610c89666817665713362a7 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x73234630bd159384c8d43f145407312d64614f43 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xad1ddf00c4ae50573e4dc98e6c5ee93baa04a0c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xa765593c821f7df9ad81119509a37961e7ffa6c5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x9b501a7ad3087d603ceb34424b7b2a6c348ad0b7 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xafebb7cfa1a15fcac4121b609b456cbce3137c20 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x0adaf134ae0c4583b3a38fc3168a83e33162651e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xf9878a5dd55edc120fde01893ea713a4f032229c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x84e47c7f2fe86f6b5efbe14fee46b8bb871b2e05 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xf3e5bec78654049990965f666b0612e116b94fb2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x33e59edd3214e97cb68450c6d3d6c167de072aba - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x2ca76c7e466e560e0cb11a91269bb953e41254bc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xbb124e35ab9e85f8d59ba83500e559dc052b9368 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x21b8065d10f73ee2e260e5b47d3344d3ced7596e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x517f9dd285e75b599234f7221227339478d0fcc8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xa43fe16908251ee70ef74718545e4fe6c5ccec9f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x0af81cd5d9c124b4859d65697a4cd10ee223746a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xca7c2771d248dcbe09eabe0ce57a62e18da178c0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x09d1d767edf8fa23a64c51fa559e0688e526812f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x7b73644935b8e68019ac6356c40661e1bc315860 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x180efc1349a69390ade25667487a826164c9c6e4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x9c4fe5ffd9a9fc5678cfbd93aa2d4fd684b67c4c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xa478c2975ab1ea89e8196811f51a7b7ade33eb11 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xbb2b8038a1640196fbe3e38816f3e67cba72d940 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x9ec9367b8c4dd45ec8e7b800b1f719251053ad60 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xc91ef786fbf6d62858262c82c63de45085dea659 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x197d7010147df7b99e9025c724f13723b29313f8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x25647e01bd0967c1b9599fa3521939871d1d0888 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x2f0b1417aa42ebf0b4ca1154212847f6094d708d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x6ada49aeccf6e556bb7a35ef0119cc8ca795294a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x2a6c340bcbb0a79d3deecd3bc5cbc2605ea9259f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xda2d09fbbf8ee4b5051a0e9b562c5fcb4b393b18 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x48d20b3e529fb3dd7d91293f80638df582ab2daa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x4028daac072e492d34a3afdbef0ba7e35d8b55c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xc2eab7d33d3cb97692ecb231a5d0e4a649cb539d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xc5be99a02c6857f9eac67bbce58df5572498f40c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xe4b8583ccb95b25737c016ac88e539d0605949e8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x8dbee21e8586ee356130074aaa789c33159921ca - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x43de4318b6eb91a7cf37975dbb574396a7b5b5c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x9ff68f61ca5eb0c6606dc517a9d44001e564bb66 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xa29fe6ef9592b5d408cca961d0fb9b1faf497d6d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x1b1137dd16faa651e38a9dfb5d9ffff7767fdf62 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x470e8de2ebaef52014a47cb5e6af86884947f08c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x8fb8e9921922d2ffb529a95d28a0d06d275d7a59 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xd3d2e2692501a5c9ca623199d38826e513033a17 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x97e1fcb93ae7267dbafad23f7b9afaa08264cfd8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xa5e9c917b4b821e4e0a5bbefce078ab6540d6b5e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x2cc846fff0b08fb3bffad71f53a60b4b6e6d6482 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x959873fb4fc11825fba83c80c4c632db1e936e15 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xa7480aafa8ad2af3ce24ac6853f960ae6ac7f0c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xc7e6b676bfc73ae40bcc4577f22aab1682c691c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x570febdf89c07f256c75686caca215289bb11cfc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x343fd171caf4f0287ae6b87d75a8964dc44516ab - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xcaa004418eb42cdf00cb057b7c9e28f0ffd840a5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xe3d3551bb608e7665472180a20280630d9e938aa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xb6b0c651c37ec4ca81c0a128420e02001a57fac2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x4e34da137f0b317c633838458e0c923a5e088752 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0xfe9e7931e55c514c33d489c88582fa36e84bd8e3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x5281e311734869c64ca60ef047fd87759397efe6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x149148acc3b06b8cc73af3a10e84189243a35925 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x8ef79d6c328c25da633559c20c75f638a4863462 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xd88d5f9e6c10e6febc9296a454f6c2589b1e8fae - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xb90fe7da36ac89448e6dfd7f2bb1e90a66659977 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xbd6313d0796984c578cae6bc5b5e23b27c5540c5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x1f18cd7d1c7ba0dbe3d9abe0d3ec84ce1ad10066 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x7da99753ff017f1b7afb2c8c0542718dc9f15f21 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x079e7a44f42e9cd2442c3b9536244be634e8f888 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x1c8dafd358d308b880f71edb5170b010b106ca60 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xbd0f6f34baa3c1329448a69bab90111a20756f01 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x3420720e561f3082f1e514a4545f0f2e0c955a5d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xea3fb6e3313a2a90757e4ca3d6749efd0107b0b6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xf130f72f8190f662522774c3367e6e8814f5e219 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x4a46c053bd5c10a959aea258228217b9d3405f3d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xb83258bf5940c98abf54f26c5a02710bd6b83b2c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x6a209c5329f0a225fa1890d4177823c096016f34 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xdb24905b1b080f65dedb0ad978aad5c76363d3c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xddff2cdad11898b901a661e32e9fa010780263a0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x72dd8fe09b5b493012e5816068dfc6fb26a2a9e6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x54fc722a66abfb6500a36d8b7b2646129d0e836a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x53b612b32233c80ec439a64325a29766ce95be7f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xe5edcbe72d1bc223097a1bed1fe6c0e404b4290c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xb928c37b8bd9754d321dc3d3c6ef374d332fe761 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x2d70cbabf4d8e61d5317b62cbe912935fd94e0fe - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x953e2937f0515c43ca7995e80c84aedcbbb9385e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x84394d80830ae963b599ded7d9149b90059f182f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xa1777e082fa1746eb78dd9c1fbb515419cf6e538 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x112466c8b6e5abe42c78c47eb1b9d40baa3f943c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x9491d57c5687ab75726423b55ac2d87d1cda2c3f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x978799f1845c00c9a4d9fd2629b9ce18df66e488 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xdc55d1fd1c04e005051a40bd59c5f95623257bc5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x34757893070b0fc5de37aaf2844255ff90f7f1e0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x7faf167615419228f3f7d71d52d840dab154913c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xa4d7b6a50dd4c55334ca6f175dbc6561f269d264 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x0ed413cefde954d8e5c54d981d7d182b587e98e3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x524375d0c6a04439128428f400b00eae81a2e9e4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x4b7a4530d56ff55a4dce089d917ede812e543307 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x84bb5b9bf1b6782c87cfa3e396f2f571c8e49646 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x723292eea7e1576ae482a5c317934054c0199e24 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x9b42940e8184d866aac6595a91f8d8952a59d3b9 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x37622453c614f625d288151101ffe48fd222ced1 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x4a94130b9e8eb0a0959c2c0f1ee9583213773fd9 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x51514b3dc24afc1db95586242b99f0063bea17c5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xc130254e9196d48bbd9f91240390a6e8203132e9 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x60ac25da2ada3be14a2a8c04e45b072bed965966 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x4e392a3883a84225260ff857318517eb50e5d128 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xca0aa06385a42242fe9523cd7015f6d01cd8f6b2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x3e448c17043ce1481bbe53c0fd19481bad8b98a6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x81060e6bf2a683f208b8799a33c7c09830cabed1 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x463fe9f646b61ccfb43a022bf947075411cd71c7 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x21b8065d10f73ee2e260e5b47d3344d3ced7596e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x517f9dd285e75b599234f7221227339478d0fcc8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xa43fe16908251ee70ef74718545e4fe6c5ccec9f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x0af81cd5d9c124b4859d65697a4cd10ee223746a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xca7c2771d248dcbe09eabe0ce57a62e18da178c0 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x09d1d767edf8fa23a64c51fa559e0688e526812f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x7b73644935b8e68019ac6356c40661e1bc315860 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x180efc1349a69390ade25667487a826164c9c6e4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x9c4fe5ffd9a9fc5678cfbd93aa2d4fd684b67c4c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xa478c2975ab1ea89e8196811f51a7b7ade33eb11 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xbb2b8038a1640196fbe3e38816f3e67cba72d940 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x9ec9367b8c4dd45ec8e7b800b1f719251053ad60 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xc91ef786fbf6d62858262c82c63de45085dea659 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x197d7010147df7b99e9025c724f13723b29313f8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x25647e01bd0967c1b9599fa3521939871d1d0888 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x2f0b1417aa42ebf0b4ca1154212847f6094d708d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x6ada49aeccf6e556bb7a35ef0119cc8ca795294a - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x2a6c340bcbb0a79d3deecd3bc5cbc2605ea9259f - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xda2d09fbbf8ee4b5051a0e9b562c5fcb4b393b18 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x48d20b3e529fb3dd7d91293f80638df582ab2daa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x4028daac072e492d34a3afdbef0ba7e35d8b55c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xc2eab7d33d3cb97692ecb231a5d0e4a649cb539d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xc5be99a02c6857f9eac67bbce58df5572498f40c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xe4b8583ccb95b25737c016ac88e539d0605949e8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x8dbee21e8586ee356130074aaa789c33159921ca - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x43de4318b6eb91a7cf37975dbb574396a7b5b5c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x9ff68f61ca5eb0c6606dc517a9d44001e564bb66 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xa29fe6ef9592b5d408cca961d0fb9b1faf497d6d - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x1b1137dd16faa651e38a9dfb5d9ffff7767fdf62 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x470e8de2ebaef52014a47cb5e6af86884947f08c - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x8fb8e9921922d2ffb529a95d28a0d06d275d7a59 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xd3d2e2692501a5c9ca623199d38826e513033a17 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x97e1fcb93ae7267dbafad23f7b9afaa08264cfd8 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xa5e9c917b4b821e4e0a5bbefce078ab6540d6b5e - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x2cc846fff0b08fb3bffad71f53a60b4b6e6d6482 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x959873fb4fc11825fba83c80c4c632db1e936e15 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xa7480aafa8ad2af3ce24ac6853f960ae6ac7f0c4 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xc7e6b676bfc73ae40bcc4577f22aab1682c691c6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x570febdf89c07f256c75686caca215289bb11cfc - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x343fd171caf4f0287ae6b87d75a8964dc44516ab - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xcaa004418eb42cdf00cb057b7c9e28f0ffd840a5 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xe3d3551bb608e7665472180a20280630d9e938aa - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xb6b0c651c37ec4ca81c0a128420e02001a57fac2 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x4e34da137f0b317c633838458e0c923a5e088752 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0xfe9e7931e55c514c33d489c88582fa36e84bd8e3 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x5281e311734869c64ca60ef047fd87759397efe6 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x149148acc3b06b8cc73af3a10e84189243a35925 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x8ef79d6c328c25da633559c20c75f638a4863462 - 2024-03-08T18:54:07.408Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/ethereum/0x0f23d49bc92ec52ff591d091b3e16c937034496e - 2024-03-08T20:34:37.448Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/arbitrum/0x0f23d49bc92ec52ff591d091b3e16c937034496e - 2024-03-08T20:34:37.448Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0xbf16ef186e715668aa29cef57e2fd7f9d48adfe6 - 2024-03-08T20:34:37.448Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/optimism/0x0f23d49bc92ec52ff591d091b3e16c937034496e - 2024-03-08T20:34:37.448Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x5645dcb64c059aa11212707fbf4e7f984440a8cf - 2024-03-08T20:34:37.448Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/polygon/0x0f23d49bc92ec52ff591d091b3e16c937034496e - 2024-03-08T20:34:37.448Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x3ad4913fa896391c9822a81d8d869cc0d783bdd7 - 2024-03-08T20:34:37.448Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/base/0x0f23d49bc92ec52ff591d091b3e16c937034496e - 2024-03-08T20:34:37.448Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/bnb/0x0f23d49bc92ec52ff591d091b3e16c937034496e - 2024-03-08T20:34:37.448Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/pools/celo/0x0f23d49bc92ec52ff591d091b3e16c937034496e - 2024-03-08T20:34:37.448Z + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x7a415b19932c0105c82fdb6b720bb01b0cc2cae3 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x9b3423373e6e786c9ac367120533abe4ee398373 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x4a25dbdf9629b1782c3e2c7de3bdce41f1c7f801 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0xbe80225f09645f172b079394312220637c440a63 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x059615ebf32c946aaab3d44491f78e4f8e97e1d3 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x435664008f38b0650fbc1c9fc971d0a3bc2f1e47 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x4b62fa30fea125e43780dc425c2be5acb4ba743b + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0xc3db44adc1fcdfd5671f555236eae49f4a8eea18 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0xddd23787a6b80a794d952f5fb036d0b31a8e6aff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0xa86aca6d7c393c06dcdc30473ea3d1b05c358dff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x1ffec7119e315b15852557f654ae0052f76e6ae1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x0f027d40c80d8f70f77d3884776531f80b21d20e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x69c66beafb06674db41b22cfc50c34a93b8d82a2 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0xeedff72a683058f8ff531e8c98575f920430fdc5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x811cfb75567a252bea23474e2ccd1286927bfe0a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x2caccf71bdf8fff97c06a46eca29b611b1a74b5e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0xf07a84f0732dfe8eea0d3961bcd8f62c761ff508 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x8c1c499b1796d7f3c2521ac37186b52de024e58c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0xe5cf22ee4988d54141b77050967e1052bd9c7f7a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x7f580f8a02b759c350e6b8340e7c2d4b8162b6a9 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x48b0ab72c2591849e678e7d6f272b75ef9b863f7 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x74d0ae8b8e1fca6039707564704a25ad2ee036b0 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x5969efdde3cf5c0d9a88ae51e47d721096a97203 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0xe32efff8f8b5fdc53803405aa3f623f03f8a8767 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0xe8629b6a488f366d27dad801d1b5b445199e2ada + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x066b28f0c160935cf285f75ed600967bf8417035 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0xddd23787a6b80a794d952f5fb036d0b31a8e6aff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0xa86aca6d7c393c06dcdc30473ea3d1b05c358dff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x1ffec7119e315b15852557f654ae0052f76e6ae1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x0f027d40c80d8f70f77d3884776531f80b21d20e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x69c66beafb06674db41b22cfc50c34a93b8d82a2 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0xeedff72a683058f8ff531e8c98575f920430fdc5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x811cfb75567a252bea23474e2ccd1286927bfe0a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x2caccf71bdf8fff97c06a46eca29b611b1a74b5e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0xf07a84f0732dfe8eea0d3961bcd8f62c761ff508 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x8c1c499b1796d7f3c2521ac37186b52de024e58c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0x146b020399769339509c98b7b353d19130c150ec + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0xd28f71e383e93c570d3edfe82ebbceb35ec6c412 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0xadab76dd2dca7ae080a796f0ce86170e482afb4a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0x0fb07e6d6e1f52c839608e1436d2ea810cf07257 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0xddd23787a6b80a794d952f5fb036d0b31a8e6aff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0xa86aca6d7c393c06dcdc30473ea3d1b05c358dff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0x1ffec7119e315b15852557f654ae0052f76e6ae1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0x0f027d40c80d8f70f77d3884776531f80b21d20e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0x69c66beafb06674db41b22cfc50c34a93b8d82a2 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0xeedff72a683058f8ff531e8c98575f920430fdc5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0x811cfb75567a252bea23474e2ccd1286927bfe0a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0x2caccf71bdf8fff97c06a46eca29b611b1a74b5e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0xf07a84f0732dfe8eea0d3961bcd8f62c761ff508 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0x8c1c499b1796d7f3c2521ac37186b52de024e58c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x95d2483d2a0fff034004f91c53d649623d993896 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x19c5505638383337d2972ce68b493ad78e315147 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0xc143161ed3ed8049bb63d8da42907c08a10e2269 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0xc3286373599dd5af2a17a572ebb7561f05f88bec + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0xbb98b3d2b18aef63a3178023a920971cf5f29be4 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x647fb01a63de9a551b39c7915693b25e6bcec502 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0xa90c1c009dc8292bd04ced30f9b53a5ff7a806a0 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0xddd23787a6b80a794d952f5fb036d0b31a8e6aff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0xa86aca6d7c393c06dcdc30473ea3d1b05c358dff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x1ffec7119e315b15852557f654ae0052f76e6ae1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x0f027d40c80d8f70f77d3884776531f80b21d20e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x69c66beafb06674db41b22cfc50c34a93b8d82a2 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0xeedff72a683058f8ff531e8c98575f920430fdc5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x811cfb75567a252bea23474e2ccd1286927bfe0a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x2caccf71bdf8fff97c06a46eca29b611b1a74b5e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0xf07a84f0732dfe8eea0d3961bcd8f62c761ff508 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x8c1c499b1796d7f3c2521ac37186b52de024e58c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xfb765ff72a14735550f1d798a5efd1311f2ddee7 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x3537f2a5f99f08f59eb1417073db1fadbebf0c74 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xde8ed0277ee0e84c25756a73ffa7374e4aeadf46 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xd8f3a72d2b2220a5067abe8c38aea57dc2d69a5e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x7ec18abf80e865c6799069df91073335935c4185 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x14b1911dd6b451c2771661ae8cd70637d726c356 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x9ae8084c21752971d867597c07f2673765d949a1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xcfaf75a3d292c3535ea3acdb16ed2ee58c2bb091 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x8055e6de251e414e8393b20adab096afb3cf8399 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xffec10fe1355c2d8df4f62affcdeffdb04f06569 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xc16454420f100b2e771d8bc4c5b6200068129a34 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x046f405e4ae1d0e786eda4959adadbd417d13ad8 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xeccb34691c06c1c9c31ceb2228b22cbd242b5879 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xe22a2dfaaaaec8a7b2b7acb4909eaaa5c5bd6e64 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xe2dda0911e227e73d9fd94745b851c8bc6504610 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x0f082a7870908f8cebbb2cd27a42a9225c19f898 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x69d667281778db0c3bc8177efea3a91ee95c3068 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x30d61bb28a6789f9f49d8c7fb198d63b6aba4b61 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x090f3fd9110621df127c3f9be5c6f58c02f2d5eb + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xd56f086e7b796b313d49f2bc926fac4bdd2a2b0b + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x7eb847a214192aab8fa1b503f4d4c9ddd2a08db6 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x81b3bc0ef974c16d71b8614adb8c22ccc045da01 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xc9b44ca4159dbaf5722a3dc8618e9d4b5f39d5b2 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xbeef35a63fc62a3334630d9d3b4db27093d95317 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x3d5d143381916280ff91407febeb52f2b60f33cf + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x68c9325cc268df8b9ed4a06429587f28471b5f84 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xa00cc1fb7ac185222294777c6b23a13c013f07ce + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x77021e63bcbd3c5296b0cdd8a3c3770fb0ea8fa2 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xcc28456d4ff980cee3457ca809a257e52cd9cdb0 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xec0b7e8e44c9d60efd67a89dba1d4a6e02a7a4a0 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x0c8fed5dd65542ca5f0add1acab14c2e470c9110 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xd56da2b74ba826f19015e6b7dd9dae1903e85da1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x5482c2b11951bbb92b87858242e17abde802b398 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xd95bae63641d822dc591bd4aca7a64e53eac76f9 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x06959273e9a65433de71f5a452d529544e07ddd0 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x24bf2ee2e09477082d1ddf2f0603baa460b3f5f3 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x56d8f846415e08c5e663d89505e79f522d33f947 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x548e923281f372d28a40287d3a2d30dce482fc66 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x9d744d3d905897608d24c1b8c1c7db0d30c36cd4 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xddd23787a6b80a794d952f5fb036d0b31a8e6aff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xa86aca6d7c393c06dcdc30473ea3d1b05c358dff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x1ffec7119e315b15852557f654ae0052f76e6ae1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x0f027d40c80d8f70f77d3884776531f80b21d20e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x69c66beafb06674db41b22cfc50c34a93b8d82a2 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xeedff72a683058f8ff531e8c98575f920430fdc5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x811cfb75567a252bea23474e2ccd1286927bfe0a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x2caccf71bdf8fff97c06a46eca29b611b1a74b5e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xf07a84f0732dfe8eea0d3961bcd8f62c761ff508 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x8c1c499b1796d7f3c2521ac37186b52de024e58c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0xab46d39cb398fb3649ecba781180016fef75f50b + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x25048028ad87484b7fce99bc4e22dcb6c3307470 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0xdb2177fee5b0ebdc7b8038cb70f3964bb6d14143 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x42d749f736051d8933b118324cded52d1f92bec1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0xb1a1b707b143b911c36e1a0f4f901c5017791aca + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x3319a81a316abd4c086f7048904e31ff86648b38 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x4a978a2d4fb7393063babfb0cee741b8bcd4dd4b + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0xea403e36fb592fdfdc342c38e94284ddbb0d2105 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0xe3fb01794d6912f0773171e32e723471ee8df061 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x916d7f23ccbb1d10118dcfc6ad5a10b6446ff73e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0xddd23787a6b80a794d952f5fb036d0b31a8e6aff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0xa86aca6d7c393c06dcdc30473ea3d1b05c358dff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x1ffec7119e315b15852557f654ae0052f76e6ae1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x0f027d40c80d8f70f77d3884776531f80b21d20e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x69c66beafb06674db41b22cfc50c34a93b8d82a2 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0xeedff72a683058f8ff531e8c98575f920430fdc5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x811cfb75567a252bea23474e2ccd1286927bfe0a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x2caccf71bdf8fff97c06a46eca29b611b1a74b5e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0xf07a84f0732dfe8eea0d3961bcd8f62c761ff508 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x8c1c499b1796d7f3c2521ac37186b52de024e58c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x6cde5f5a192fbf3fd84df983aa6dc30dbd9f8fac + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xd80d28850bebe6208433c298334392bc940b4fc7 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x7f7c4335ccac291ddedcef4429a626c442b627ed + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x628cb3a5a206956423d158009612813b64b19dab + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x116361f4f45e310347b43cd098fdfa459760ea7f + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x5dc631ad6c26bea1a59fbf2c2680cf3df43d249f + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x1a810e0b6c2dd5629afa2f0c898b9512c6f78846 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xac1cb6d3d419da9ead0b53e62d6fb4bb53473523 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x0115d04a88990889471a88e85817aac9e961c07b + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xd3409b7f3f54bb097433d0f4cd31c48ac33e569b + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x493bfc1adb2e60805693197f23132350ffd2a04e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xcf4f103759770c21f945413781ca787620316988 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xb135ebde27d366b0d62e579bae4118cb991b820e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xecbc2f008c20729b9239317408367377c5473812 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x96e0c440d3377c2dfe4f2a82add0b045e46cbe64 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x6f5304c22ac77e228e8af4732ac6677c46e09030 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xcb037f27eb3952222810966e28e0ceb650c65cd9 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xddd23787a6b80a794d952f5fb036d0b31a8e6aff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xa86aca6d7c393c06dcdc30473ea3d1b05c358dff + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x1ffec7119e315b15852557f654ae0052f76e6ae1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x0f027d40c80d8f70f77d3884776531f80b21d20e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x69c66beafb06674db41b22cfc50c34a93b8d82a2 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xeedff72a683058f8ff531e8c98575f920430fdc5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x811cfb75567a252bea23474e2ccd1286927bfe0a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x2caccf71bdf8fff97c06a46eca29b611b1a74b5e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xf07a84f0732dfe8eea0d3961bcd8f62c761ff508 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x8c1c499b1796d7f3c2521ac37186b52de024e58c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x7baece5d47f1bc5e1953fbe0e9931d54dab6d810 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x83abecf7204d5afc1bea5df734f085f2535a9976 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x4eefe02fce5b53ca33c7717bbd8ad3c9cb0609f1 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0xaf996125e98b5804c00ffdb4f7ff386307c99a00 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/ethereum/0x7924a818013f39cf800f5589ff1f1f0def54f31f + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0xb2eb5849e2606f99fc492e9add0103c667f806d3 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x53c6ca2597711ca7a73b6921faf4031eedf71339 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x4eefe02fce5b53ca33c7717bbd8ad3c9cb0609f1 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0xaf996125e98b5804c00ffdb4f7ff386307c99a00 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/arbitrum/0x7924a818013f39cf800f5589ff1f1f0def54f31f + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0xd35937ecd47b04a1474f8569f457fc5ac395921a + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0x4eefe02fce5b53ca33c7717bbd8ad3c9cb0609f1 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0xaf996125e98b5804c00ffdb4f7ff386307c99a00 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/optimism/0x7924a818013f39cf800f5589ff1f1f0def54f31f + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x6b75f2189f0e11c52e814e09e280eb1a9a8a094a + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0xb372b5abdb7c2ab8ad9e614be9835a42d0009153 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0xf369277650ad6654f25412ea8bfbd5942733babc + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x4eefe02fce5b53ca33c7717bbd8ad3c9cb0609f1 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0xaf996125e98b5804c00ffdb4f7ff386307c99a00 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/polygon/0x7924a818013f39cf800f5589ff1f1f0def54f31f + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x4898cf312fbff8814cab80a8d7f6ee5ad0dc73fb + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x5e78afc6c804d4382bede3a0712d210e657e9b4f + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x86b211ca7915a0c8d4659dd98242d9e801d88ab4 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xb637f7c82fd774c280e23cebc725e7cd807c66d0 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xd249c43faabc58d6dd4b0a4de598b5a956c5d8d7 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x1fbae785ce68b79f7ed4f7b27c3af3ef0e0bc3d4 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x3c1376fb8487da57d4ffb263d9d01b578c7b586b + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x7b24bed19856f4bb1d4c0421cfb328026cd936bd + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x7cf887a863d81e6a483ee947dee05cb51914923c + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x588c8cf031809486f015908864ee8699b44017e4 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x3987d38a4ff8520a8ef6bcc6f98d6da8bcd69b89 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x4eefe02fce5b53ca33c7717bbd8ad3c9cb0609f1 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0xaf996125e98b5804c00ffdb4f7ff386307c99a00 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/base/0x7924a818013f39cf800f5589ff1f1f0def54f31f + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0xde67d05242b18af00b28678db34feec883cc9cd6 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x4eefe02fce5b53ca33c7717bbd8ad3c9cb0609f1 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0xaf996125e98b5804c00ffdb4f7ff386307c99a00 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/bnb/0x7924a818013f39cf800f5589ff1f1f0def54f31f + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x4a5a8b0108f446df7c1c8a459fcfb54e844b7343 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xf6ba006abf768ab2d1b5bba2d22d9f13eb1269d4 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x4eefe02fce5b53ca33c7717bbd8ad3c9cb0609f1 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0xaf996125e98b5804c00ffdb4f7ff386307c99a00 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/pools/celo/0x7924a818013f39cf800f5589ff1f1f0def54f31f + 2024-05-24T23:13:47.908Z 0.8 \ No newline at end of file diff --git a/apps/web/public/tokens-sitemap.xml b/apps/web/public/tokens-sitemap.xml index fa34f636c78..4660e0ebe92 100644 --- a/apps/web/public/tokens-sitemap.xml +++ b/apps/web/public/tokens-sitemap.xml @@ -2,2277 +2,3592 @@ https://app.uniswap.org/explore/tokens/ethereum/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xdac17f958d2ee523a2206206994597c13d831ec7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x2260fac5e5542a773aa44fbcfedf7c193bc2c599 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x6982508145454ce325ddbe47a25d4ec3d2311933 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x6b175474e89094c44da98b954eedeac495271d0f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x6123b0049f904d730db3c36a31167d9d4121fa6b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x1f9840a85d5af5bf1d1762f925bdaddc4201f984 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xcf0c122c6b73ff809c693db761e7baebe62b6a2e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xfaba6f8e4a5e8ab82f62fe7c39859fa577269be3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x58cb30368ceb2d194740b144eab4c2da8a917dcb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x4c9edd5852cd905f086c759e8383e09bff1e68b3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xaaee1a9723aadb7afa2810263653a34ba2c21c7a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x514910771af9ca656af840dff83e8264ecf986ca - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x5b7533812759b45c2b44c19e320ba2cd2681b542 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xae78736cd615f374d3085123a210448e74fc6393 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xb9f599ce614feb2e1bbe58f180f370d05b39344e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xd5f7838f5c461feff7fe49ea5ebaf7728bb0adfa - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xd31a59c85ae9d8edefec411d448f90841571b89c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x6a7eff1e2c355ad6eb91bebb5ded49257f3fed98 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x576e2bed8f7b46d34016198911cdf9886f78bea7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x1258d60b224c0c5cd888d37bbf31aa5fcfb7e870 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x62d0a8458ed7719fdaf978fe5929c6d342b0bfce - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x77e06c9eccf2e797fd462a92b6d7642ef85b0a44 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x24fcfc492c1393274b6bcd568ac9e225bec93584 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x27702a26126e0b3702af63ee09ac4d1a084ef628 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xd46ba6d942050d489dbd938a2c909a5d5039a161 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xbe9895146f7af43049ca1c1ae358b0541ea49704 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x72f713d11480dcf08b37e1898670e736688d218d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x0001a500a6b18995b03f44bb040a5ffc28e45cb0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x9e9fbde7c7a83c43913bddc8779158f1368f0413 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x5f98805a4e8be255a32880fdec7f6728c6568ba0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x2b591e99afe9f32eaa6214f7b7629768c40eeb39 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x1ae7e1d0ce06364ced9ad58225a1705b3e5db92b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x046eee2cc3188071c02bfc1745a6b17c656e3f3d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x84018071282d4b2996272659d9c01cb08dd7327f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x12970e6868f88f6557b76120662c1b3e50a646bf - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xaea46a60368a7bd060eec7df8cba43b7ef41ad85 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x6de037ef9ad2725eb40118bb1702ebb27e4aeb24 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xc01154b4ccb518232d6bbfc9b9e6c5068b766f82 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x5a98fcbea516cf06857215779fd812ca3bef1b32 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x102c776ddb30c754ded4fdcc77a19230a60d4e4f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x72e4f9f808c49a2a61de9c5896298920dc4eeea9 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x467719ad09025fcc6cf6f8311755809d45a5e5f3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xf19308f923582a6f7c465e5ce7a9dc1bec6665b1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x710287d1d39dcf62094a83ebb3e736e79400068a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xf951e335afb289353dc249e82926178eac7ded78 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xf017d3690346eb8234b85f74cee5e15821fee1f4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x8c282c35b5e1088bb208991c151182a782637699 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xeaa63125dd63f10874f99cdbbb18410e7fc79dd3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xde342a3e269056fc3305f9e315f4c40d917ba521 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x2dff88a56767223a5529ea5960da7a3f5f766406 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x626e8036deb333b408be468f951bdb42433cbf18 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xdd66781d0e9a08d4fbb5ec7bac80b691be27f21d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xb23d80f5fefcddaa212212f028021b41ded428cf - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xbaac2b4491727d78d2b78815144570b9f2fe8899 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xf8ebf4849f1fa4faf0dff2106a173d3a6cb2eb3a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xb90b2a35c65dbc466b04240097ca756ad2005295 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x1614f18fc94f47967a3fbe5ffcd46d4e7da3d787 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xf1df7305e4bab3885cab5b1e4dfc338452a67891 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x91fbb2503ac69702061f1ac6885759fc853e6eae - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xa9e8acf069c58aec8825542845fd754e41a9489a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x2c95d751da37a5c1d9c5a7fd465c1d50f3d96160 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xe453c3409f8ad2b1fe1ed08e189634d359705a5b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x89d584a1edb3a70b3b07963f9a3ea5399e38b136 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x4507cef57c46789ef8d1a19ea45f4216bae2b528 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xd1d2eb1b1e90b638588728b4130137d262c87cae - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xe92344b4edf545f3209094b192e46600a19e7c2d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x8a0a9b663693a22235b896f70a229c4a22597623 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x1bbe973bef3a977fc51cbed703e8ffdefe001fed - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xa41d2f8ee4f47d3b860a149765a7df8c3287b7f0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x761d38e5ddf6ccf6cf7c55759d5210750b5d60f3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xc18360217d8f7ab5e7c516566761ea12ce7f9d72 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xe28b3b32b6c345a34ff64674606124dd5aceca30 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x168e209d7b2f58f1f24b8ae7b7d35e662bbf11cc - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xb131f4a55907b10d1f0a50d8ab8fa09ec342cd74 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x3472a5a71965499acd81997a54bba8d852c6e53d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x7dd9c5cba05e151c895fde1cf355c9a1d5da6429 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x19efa7d0fc88ffe461d1091f8cbe56dc2708a84f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x14fee680690900ba0cccfc76ad70fd1b95d10e16 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x3c3a81e81dc49a522a592e7622a7e711c06bf354 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xa1290d69c65a6fe4df752f95823fae25cb99e5a7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x92f419fb7a750aed295b0ddf536276bf5a40124f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x2c06ba9e7f0daccbc1f6a33ea67e85bb68fbee3a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x3d658390460295fb963f54dc0899cfb1c30776df - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x8e870d67f660d95d5be530380d0ec0bd388289e1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x853d955acef822db058eb8505911ed77f175b99e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x1294f4183763743c7c9519bec51773fb3acd78fd - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x4e15361fd6b4bb609fa63c81a2be19d873717870 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x695d38eb4e57e0f137e36df7c1f0f2635981246b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x40a7df3df8b56147b781353d379cb960120211d7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xaaef88cea01475125522e117bfe45cf32044e238 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x163f8c2467924be0ae7b5347228cabf260318753 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x30672ae2680c319ec1028b69670a4a786baa0f35 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xc944e90c64b2c07662a292be6244bdf05cda44a7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x15e6e0d4ebeac120f9a97e71faa6a0235b85ed12 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x7d225c4cc612e61d26523b099b0718d03152edef - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x82af49447d8a07e3bd95bd0d56f35241523fbab1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xaf88d065e77c8cc2239327c5edb3a432268e5831 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xff970a61a04b1ca14834a43f5de4533ebddb5cc8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x912ce59144191c1204e64559fe8253a0e49e6548 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x5979d7b546e38e414f7e9822514be443a4800529 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x35751007a407ca6feffe80b3cb397736d2cf4dbe - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xda10009cbd5d07dd0cecc66161fc93d7c9000da1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xeb466342c4d449bc9f53a865d5cb90586f405215 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xfc5a1a6eb076a2c7ad06ed22c90d7e710e35ad0a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x0c880f6761f1af8d9aa9c466984b80dab9a8c9e8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xf97f4df75117a78c1a5a0dbb814af92458539fb4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x9623063377ad1b27544c965ccd7342f7ea7e88c7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x539bde0d7dbd336b79148aa742883198bbf60342 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x3082cc23568ea640225c2467653db90e9250aaa0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x18c11fd286c5ec11c3b683caa813b77f5163a122 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x289ba1701c2f088cf0faf8b3705246331cb8a839 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x4cb9a7ae498cedcbb5eae9f25736ae7d428c9d66 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x00cbcf7b3d37844e44b888bc747bdd75fcf4e555 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xfa7f8980b0f1e64a2062791cc3b0871572f1f7f0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xd79bb960dc8a206806c3a428b31bca49934d18d7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x3096e7bfd0878cc65be71f8899bc4cfb57187ba3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x13ad51ed4f1b7e9dc168d8a00cb3f4ddd85efa60 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x4e352cf164e64adcbad318c3a1e222e9eba4ce42 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x11cdb42b0eb46d95f990bedd4695a6e3fa034978 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xba5ddd1f9d7f570dc94a51479a000e3bce967196 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xc8ccbd97b96834b976c995a67bf46e5754e2c48e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xd07d35368e04a839dee335e213302b21ef14bb4a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x323665443cef804a3b5206103304bd4872ea4253 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x83d6c8c06ac276465e4c92e7ac8c23740f435140 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x87aaffdf26c6885f6010219208d5b161ec7609c0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x1b8d516e2146d7a32aca0fcbf9482db85fd42c3a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xafccb724e3aec1657fc9514e3e53a0e71e80622d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x4425742f1ec8d98779690b5a3a6276db85ddc01a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x3419875b4d3bca7f3fdda2db7a476a79fd31b4fe - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x3b60ff35d3f7f62d636b067dd0dc0dfdad670e4e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x58b9cb810a68a7f3e1e4f8cb45d1b9b3c79705e8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xfa5ed56a203466cbbc2430a43c66b9d8723528e7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x95146881b86b3ee99e63705ec87afe29fcc044d9 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x088cd8f5ef3652623c22d48b1605dcfe860cd704 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xbfd5206962267c7b4b4a8b3d76ac2e1b2a5c4d5e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x6daf586b7370b14163171544fca24abcc0862ac5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x9d2f299715d94d8a7e6f5eaa8e654e8c74a988a7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x580e933d90091b9ce380740e3a4a39c67eb85b4c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x655a6beebf2361a19549a99486ff65f709bd2646 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x9e64d3b9e8ec387a9a58ced80b71ed815f8d82b5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x2297aebd383787a160dd0d9f71508148769342e3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x6694340fc020c5e6b96567843da2df01b2ce1eb6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x772598e9e62155d7fdfe65fdf01eb5a53a8465be - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x431402e8b9de9aa016c743880e04e517074d8cec - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xd74f5255d557944cf7dd0e45ff521520002d5748 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x6fd58f5a2f3468e35feb098b5f59f04157002407 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x561877b6b3dd7651313794e5f2894b2f18be0766 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xf9ca0ec182a94f6231df9b14bd147ef7fb9fa17c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xd77b108d4f6cefaa0cae9506a934e825becca46e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xd56734d7f9979dd94fae3d67c7e928234e71cd4c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xf1264873436a0771e440e2b28072fafcc5eebd01 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x5575552988a3a80504bbaeb1311674fcfd40ad4b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x0341c0c0ec423328621788d4854119b97f44e391 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x764bfc309090e7f93edce53e5befa374cdcb7b8e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xaaa6c1e32c55a7bfa8066a6fae9b42650f262418 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x9e20461bc2c4c980f62f1b279d71734207a6a356 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x7fb7ede54259cb3d4e1eaf230c7e2b1ffc951e9a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x3a18dcc9745edcd1ef33ecb93b0b6eba5671e7ca - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x000000000026839b3f4181f2cf69336af6153b99 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x8b0e6f19ee57089f7649a455d89d7bc6314d04e8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x31c91d8fb96bff40955dd2dbc909b36e8b104dde - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x25d887ce7a35172c62febfd67a1856f20faebb00 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xd4d42f0b6def4ce0383636770ef773390d85c61a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xf8388c2b6edf00e2e27eef5200b1befb24ce141d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x619c82392cb6e41778b7d088860fea8447941f4c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x94025780a1ab58868d9b2dbbb775f44b32e8e6e5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xad4b9c1fbf4923061814dd9d5732eb703faa53d4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xd7a892f28dedc74e6b7b33f93be08abfc394a360 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x3269a3c00ab86c753856fd135d97b87facb0d848 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x4568ca00299819998501914690d6010ae48a59ba - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x21e60ee73f17ac0a411ae5d690f908c3ed66fe12 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xd3188e0df68559c0b63361f6160c57ad88b239d8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x2b41806cbf1ffb3d9e31a9ece6b738bf9d6f645f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xf19547f9ed24aa66b03c3a552d181ae334fbb8db - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x35e6a59f786d9266c7961ea28c7b768b33959cbb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x59a729658e9245b0cf1f8cb9fb37945d2b06ea27 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xb56c29413af8778977093b9b4947efeea7136c36 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x43ab8f7d2a8dd4102ccea6b438f6d747b1b9f034 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x1d987200df3b744cfa9c14f713f5334cb4bc4d5d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x3404149e9ee6f17fb41db1ce593ee48fbdcd9506 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x080f6aed32fc474dd5717105dba5ea57268f46eb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xb5a628803ee72d82098d4bcaf29a42e63531b441 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x1622bf67e6e5747b81866fe0b85178a93c7f86e3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x7dd747d63b094971e6638313a6a2685e80c7fb2e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xa2f9ecf83a48b86265ff5fd36cdbaaa1f349916c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x17a8541b82bf67e10b0874284b4ae66858cb1fd5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xbcd4d5ac29e06e4973a1ddcd782cd035d04bc0b7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x42069d11a2cc72388a2e06210921e839cfbd3280 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xbbea044f9e7c0520195e49ad1e561572e7e1b948 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xe85b662fe97e8562f4099d8a1d5a92d4b453bf30 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x3d9907f9a368ad0a51be60f7da3b97cf940982d8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0x4e51ac49bc5e2d87e0ef713e9e5ab2d71ef4f336 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x4200000000000000000000000000000000000006 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x7f5c764cbc14f9669b88837ca1490cca17c31607 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x4200000000000000000000000000000000000042 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x0b2c639c533813f4aa9d7837caf62653d097ff85 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x1f32b1c2345538c0c6f582fcb022739c4a194ebb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x68f180fcce6836688e9084f035309e29bf0a2095 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x94b008aa00579c1307b0ef2c499ad98a8ce58e58 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0xda10009cbd5d07dd0cecc66161fc93d7c9000da1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0xdc6ff44d5d932cbd77b52e5612ba0529dc6226f1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x8c6f28f2f1a3c87f0f938b96d27520d9751ec8d9 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x8700daec35af8ff88c16bdf0418774cb3d7599b4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x920cf626a271321c151d027030d5d08af699456b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x6c84a8f1c29108f47a79964b5fe888d4f4d0de40 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x9e1028f5f1d5ede59748ffcee5532509976840e0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0xeb466342c4d449bc9f53a865d5cb90586f405215 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x350a791bfc2c21f9ed5d10980dad2e2638ffa7f6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x17aabf6838a6303fc6e9c5a227dc1eb6d95c829a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0xf467c7d5a4a9c4687ffc7986ac6ad5a4c81e1404 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x76fb31fb4af56892a25e32cfc43de717950c9278 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0xc5b001dc33727f8f26880b184090d3e252470d45 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x9560e827af36c94d2ac33a39bce1fe78631088db - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x9bcef72be871e61ed4fbbc7630889bee758eb81d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x50c5725949a6f0c72e6c4a641f24049a917db0cb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0xf98dcd95217e15e05d8638da4c91125e59590b07 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x4b03afc91295ed778320c2824bad5eb5a1d852dd - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0xc40f949f8a4e094d1b49a23ea9241d289b7b2819 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x323665443cef804a3b5206103304bd4872ea4253 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x50bce64397c75488465253c0a034b8097fea6578 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x296f55f8fb28e498b858d0bcda06d955b2cb3f97 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x2598c30330d5771ae9f983979209486ae26de875 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x0994206dfe8de6ec6920ff4d779b0d950605fb53 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0xc3248a1bd9d72fa3da6e6ba701e58cbf818354eb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x6fd9d7ad17242c41f7131d257212c54a0e816691 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x14778860e937f509e651192a90589de711fb88a9 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0xdfa46478f9e5ea86d57387849598dbfb2e964b02 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x9b88d293b7a791e40d36a39765ffd5a1b9b5c349 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x3eb398fec5f7327c6b15099a9681d9568ded2e82 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x217d47011b23bb961eb6d93ca9945b7501a5bb11 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0xbfd5206962267c7b4b4a8b3d76ac2e1b2a5c4d5e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x1cef2d62af4cd26673c7416957cc4ec619a696a7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x9fd22a17b4a96da3f83797d122172c450381fb88 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0xaddb6a0412de1ba0f936dcaeb8aaa24578dcf3b2 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x2791bca1f2de4661ed88a30c99a7a9449aa84174 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x7ceb23fd6bc0add59e62ac25578270cff1b9f619 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x3c499c542cef5e3811e1192ce70d8cc03d5c3359 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xc2132d05d31c914a87c6611c10748aeb04b58e8f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x61299774020da444af134c82fa83e3810b309991 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xd6df932a45c0f255f85145f286ea0b292b21c90b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x2ad2934d5bfb7912304754479dd1f096d5c807da - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xc3c7d422809852031b44ab29eec9f1eff2a58756 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x8f3cf7ad23cd3cadbd9735aff958023239c6a063 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x750e4c4984a9e0f12978ea6742bc1c5d248f40ed - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x111111517e4929d3dcbdfa7cce55d30d4b6bc4d6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xd0258a3fd00f38aa8090dfee343f10a9d4d30d3f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x430ef9263e76dae63c84292c3409d61c598e9682 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xb33eaad8d922b1083446dc23f610c2567fb5180f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xdc3326e71d45186f113a2f448984ca0e8d201995 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x311434160d7537be358930def317afb606c0d737 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x0b3f868e0be5597d5db7feb59e1cadbb0fdda50a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xe3f2b1b2229c0333ad17d03f179b87500e7c5e01 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xac0f66379a6d7801d7726d5a943356a172549adb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xf88332547c680f755481bf489d890426248bb275 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xe5417af564e4bfda1c483642db72007871397896 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xe261d618a959afffd53168cd07d12e37b26761db - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xe0b52e49357fd4daf2c15e02058dce6bc0057db4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xbbba073c31bf03b8acf7c28ef0738decf3695683 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xe238ecb42c424e877652ad82d8a939183a04c35f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x3b56a704c01d650147ade2b8cee594066b3f9421 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x5fe2b58c013d7601147dcdd68c143a77499f5531 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x172370d5cd63279efa6d502dab29171933a610af - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x53df32548214f51821cf1fe4368109ac5ddea1ff - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xff76c0b48363a7c7307868a81548d340049b0023 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x6f8a06447ff6fcf75d803135a7de15ce88c1d4ec - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x50b728d8d964fd00c2d0aad81718b71311fef68a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xd93f7e271cb87c23aaa73edc008a79646d1f9912 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x200c234721b5e549c3693ccc93cf191f90dc2af9 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x11cd37bb86f65419713f30673a480ea33c826872 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x8a16d4bf8a0a716017e8d2262c4ac32927797a2f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x9a71012b13ca4d3d0cdc72a177df3ef03b0e76a3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xa1c57f48f0deb89f569dfbe6e2b7f46d33606fd4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x190eb8a183d22a4bdf278c6791b152228857c033 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x2f6f07cdcf3588944bf4c42ac74ff24bf56e7590 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x235737dbb56e8517391473f7c964db31fa6ef280 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x0b220b82f3ea3b7f6d9a1d8ab58930c064a2b5bf - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x8bff1bd27e2789fe390acabc379c380a83b68e84 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xb58458c52b6511dc723d7d6f3be8c36d7383b4a8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x323665443cef804a3b5206103304bd4872ea4253 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x2760e46d9bb43dafcbecaad1f64b93207f9f0ed7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x18ec0a6e18e5bc3784fdd3a3634b31245ab704f6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x431d5dff03120afa4bdf332c61a6e1766ef37bdb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x6f7c932e7684666c9fd1d44527765433e01ff61d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xeee3371b89fc43ea970e908536fcddd975135d8a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xe5b49820e5a1063f6f4ddf851327b5e8b2301048 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xaa3717090cddc9b227e49d0d84a28ac0a996e6ff - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x62a872d9977db171d9e213a5dc2b782e72ca0033 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x381caf412b45dac0f62fbeec89de306d3eabe384 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xe0bceef36f3a6efdd5eebfacd591423f8549b9d5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x23d29d30e35c5e8d321e1dc9a8a61bfd846d4c5c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x282d8efce846a88b159800bd4130ad77443fa1a1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x74dd45dd579cad749f9381d6227e7e02277c944b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x714db550b574b3e927af3d93e26127d15721d4c2 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xfa68fb4628dff1028cfec22b4162fccd0d45efb6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xe631dabef60c37a37d70d3b4f812871df663226f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xdb725f82818de83e99f1dac22a9b5b51d3d04dd4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x3c59798620e5fec0ae6df1a19c6454094572ab92 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x0d0b8488222f7f83b23e365320a4021b12ead608 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xa380c0b01ad15c8cf6b46890bddab5f0868e87f3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x8a953cfe442c5e8855cc6c61b1293fa648bae472 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x45c32fa6df82ead1e2ef74d17b76547eddfaff89 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x11cd72f7a4b699c67f225ca8abb20bc9f8db90c7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x0c9c7712c83b3c70e7c5e11100d33d9401bdf9dd - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x77a6f2e9a9e44fd5d5c3f9be9e52831fc1c3c0a0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xbfc70507384047aa74c29cdc8c5cb88d0f7213ac - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xfcb54da3f4193435184f3f647467e12b50754575 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x9a6a40cdf21a0af417f1b815223fd92c85636c58 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xe111178a87a3bff0c8d18decba5798827539ae99 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x82617aa52dddf5ed9bb7b370ed777b3182a30fd1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x2ab0e9e4ee70fff1fb9d67031e44f6410170d00e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xa486c6bc102f409180ccb8a94ba045d39f8fc7cb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xc4a206a306f0db88f98a3591419bc14832536862 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xf0059cc2b3e980065a906940fbce5f9db7ae40a7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x16eccfdbb4ee1a85a33f3a9b21175cd7ae753db4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x553d3d295e0f695b9228246232edf400ed3560b5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x14af1f2f02dccb1e43402339099a05a5e363b83c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x7bdf330f423ea880ff95fc41a280fd5ecfd3d09f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x8505b9d2254a7ae468c0e9dd10ccea3a837aef5c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xe2aa7db6da1dae97c5f5c6914d285fbfcc32a128 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xb7b31a6bc18e48888545ce79e83e06003be70930 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x1631244689ec1fecbdd22fb5916e920dfc9b8d30 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xf6372cdb9c1d3674e83842e3800f2a62ac9f3c66 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x692ac1e363ae34b6b489148152b12e2785a3d8d6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x0266f4f08d82372cf0fcbccc0ff74309089c74d1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x7fbc10850cae055b27039af31bd258430e714c62 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xa3fa99a148fa48d14ed51d610c367c61876997f1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x9dbfc1cbf7a1e711503a29b4b5f9130ebeccac96 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0x236aa50979d5f3de3bd1eeb40e81137f22ab794b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/polygon/0xf86df9b91f002cfeb2aed0e6d05c4c4eaef7cf02 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x4200000000000000000000000000000000000006 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x6921b130d297cc43754afba22e5eac0fbf8db75b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x5babfc2f240bc5de90eb7e19d789412db1dec402 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x532f27101965dd16442e59d40670faf5ebb142e4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x4ed4e862860bed51a9570b96d89af5e1b0efefed - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0xc1cba3fcea344f92d9239c08c0568f6f2f0ee452 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0xac1bd2486aaf3b5c0fc3fd868558b082a531b2b4 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x0d97f261b1e88845184f678e2d1e7a98d9fd38de - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x8129b94753f22ec4e62e2c4d099ffe6773969ebc - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x3f14920c99beb920afa163031c4e47a3e03b3e4a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x940181a94a35a4569e4529a3cdfb74e38fd98631 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x3419875b4d3bca7f3fdda2db7a476a79fd31b4fe - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0xa067436db77ab18b1a315095e4b816791609897c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0xafb89a09d82fbde58f18ac6437b3fc81724e4df6 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x489fe42c267fe0366b16b0c39e7aeef977e841ef - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0xdc46c1e93b71ff9209a0f8076a9951569dc35855 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x91f45aa2bde7393e0af1cc674ffe75d746b93567 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x236aa50979d5f3de3bd1eeb40e81137f22ab794b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0xf6e932ca12afa26665dc4dde7e27be02a7c02e50 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x524d524b4c9366be706d3a90dcf70076ca037ae3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x5b5dee44552546ecea05edea01dcd7be7aa6144a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x2598c30330d5771ae9f983979209486ae26de875 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0xfa980ced6895ac314e7de34ef1bfae90a5add21b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x469fda1fb46fcb4befc0d8b994b516bd28c87003 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x4e496c0256fb9d4cc7ba2fdf931bc9cbb7731660 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x27d2decb4bfc9c76f0309b8e88dec3a601fe25a8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0xbfd5206962267c7b4b4a8b3d76ac2e1b2a5c4d5e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x9e1028f5f1d5ede59748ffcee5532509976840e0 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x3c3aa127e6ee3d2f2e432d0184dd36f2d2076b52 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0xba5e6fa2f33f3955f0cef50c63dcc84861eab663 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x97c806e7665d3afd84a8fe1837921403d59f3dcc - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x8ee73c484a26e0a5df2ee2a4960b789967dd0415 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x00e57ec29ef2ba7df07ad10573011647b2366f6d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x8f019931375454fe4ee353427eb94e2e0c9e0a8c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0x93e6407554b2f02640ab806cd57bd83e848ec65d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x55d398326f99059ff775485246999027b3197955 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x2170ed0880ac9a755fd29b2688956bd959f933f8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xfdc66a08b0d0dc44c17bbd471b88f49f50cdd20f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x7130d2a12b9bcbfae4f2634d864a1ee1ce3ead9c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x1d2f0da169ceb9fc7b3144628db156f3f6c60dbe - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xe9e7cea3dedca5984780bafc599bd69add087d56 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xfa54ff1a158b5189ebba6ae130ced6bbd3aea76e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x570a5d26f7765ecb712c0924e4de545b89fd43df - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x47c454ca6be2f6def6f32b638c80f91c9c3c5949 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xad86d0e9764ba90ddd68747d64bffbd79879a238 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xf8a0bf9cf54bb92f17374d9e9a321e6a111a51bd - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xd691d9a68c887bdf34da8c36f63487333acfd103 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x1294f4183763743c7c9519bec51773fb3acd78fd - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xb04906e95ab5d797ada81508115611fee694c2b3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x111111111117dc0aa78b770fa6a738034120c302 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xcc42724c6683b7e57334c4e856f4c9965ed682bd - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x90c97f71e18723b0cf0dfa30ee176ab653e89f40 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x2b72867c32cf673f7b02d208b26889fed353b1f8 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x031b41e504677879370e9dbcf937283a8691fa7f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x1ce0c2827e2ef14d5c4f29a091d735a204794041 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xcf3bb6ac0f6d987a5727e2d15e39c2d6061d5bec - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x8ff795a6f4d97e7887c79bea79aba5cc76444adf - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x2dff88a56767223a5529ea5960da7a3f5f766406 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x003d87d02a2a01e9e8a20f507c83e15dd83a33d1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x4b0f1812e5df2a09796481ff14017e6005508003 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xbf5140a22578168fd562dccf235e5d43a02ce9b1 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xca1c644704febf4ab81f85daca488d1623c28e63 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x51e72dd1f2628295cc2ef931cb64fdbdc3a0c599 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xbbca42c60b5290f2c48871a596492f93ff0ddc82 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x555296de6a86e72752e5c5dc091fe49713aa145c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x0808bf94d57c905f1236212654268ef82e1e594e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x8457ca5040ad67fdebbcc8edce889a335bc0fbfb - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xcebef3df1f3c5bfd90fde603e71f31a53b11944d - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x90ed8f1dc86388f14b64ba8fb4bbd23099f18240 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x9840652dc04fb9db2c43853633f0f62be6f00f98 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xba2ae424d960c26247dd6c32edc70b295c744c43 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x0782b6d8c4551b9760e74c0545a9bcd90bdc41e5 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xbe2b6c5e31f292009f495ddbda88e28391c9815e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x8f0528ce5ef7b51152a59745befdd91d97091d2f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xffeecbf8d7267757c2dc3d13d730e97e15bfdf7f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x0eb3a705fc54725037cc9e008bdede697f62f335 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xf21768ccbc73ea5b6fd3c687208a7c2def2d966e - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x0000028a2eb8346cd5c0267856ab7594b7a55308 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x76a797a59ba2c17726896976b7b3747bfd1d220f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xc79d1fd14f514cd713b5ca43d288a782ae53eab2 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xad29abb318791d579433d831ed122afeaf29dcfe - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x3203c9e46ca618c8c1ce5dc67e7e9d75f5da2377 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xdb021b1b247fe2f1fa57e0a87c748cc1e321f07f - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x7083609fce4d1d8dc0c979aab8c869ea2c873402 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xc5f0f7b66764f6ec8c8dff7ba683102295e16409 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xe29142e14e52bdfbb8108076f66f49661f10ec10 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0xb0d502e938ed5f4df2e681fe6e419ff29631d62b - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x6730f7a6bbb7b9c8e60843948f7feb4b6a17b7f7 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/bnb/0x1613957159e9b0ac6c80e824f7eea748a32a0ae2 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/celo/0x471ece3750da237f93b8e339c536989b8978a438 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/celo/0x765de816845861e75a25fca122bb6898b8b1282a - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/celo/0x66803fb87abd4aac3cbb3fad7c3aa01f6f3fb207 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/celo/0xd8763cba276a3738e6de85b4b3bf5fded6d6ca73 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/celo/0x37f750b7cc259a2f741af45294f6a16572cf5cad - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/celo/0xd71ffd0940c920786ec4dbb5a12306669b5b81ef - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/celo/0xe8537a3d056da446677b9e9d6c5db704eaab4787 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/celo/0x4f604735c1cf31399c6e711d5962b2b3e0225ad3 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/celo/0x02de4766c272abc10bc88c220d214a26960a7e92 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/celo/0xceba9300f2b948710d2653dd7b07f33a8b32118c - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/celo/0xc16b81af351ba9e64c1a069e3ab18c244a1e3049 - 2024-03-08T18:44:55.418Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x728f30fa2f100742c7949d1961804fa8e0b1387d - 2024-03-08T20:33:55.117Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0x41ea5d41eeacc2d5c4072260945118a13bb7ebce - 2024-03-08T20:33:55.117Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/ethereum/0xf21661d0d1d76d3ecb8e1b9f1c923dbfffae4097 - 2024-03-08T20:33:55.117Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/arbitrum/0xb0ecc6ac0073c063dcfc026ccdc9039cae2998e1 - 2024-03-08T20:33:55.117Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/optimism/0x00f932f0fe257456b32deda4758922e56a4f4b42 - 2024-03-08T20:33:55.117Z + 2024-05-20T17:20:52.753Z 0.8 https://app.uniswap.org/explore/tokens/base/0xa4af354d466e8a68090dd9eb2cb7caf162f4c8c2 - 2024-03-08T20:33:55.117Z + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xba50933c268f567bdc86e1ac131be072c6b0b71a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xd29da236dd4aac627346e1bba06a619e8c22d7c5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x1bfce574deff725a3f483c334b790e25c8fa9779 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x9e18d5bab2fa94a6a95f509ecb38f8f68322abd3 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xbf5495efe5db9ce00f80364c8b423567e58d2110 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x065b4e5dfd50ac12a81722fd0a0de81d78ddf7fb + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x57e114b691db790c35207b2e685d4a43181e6061 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x0b7f0e51cd1739d6c96982d55ad8fa634dd43a9c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xc56c7a0eaa804f854b536a5f3d5f49d2ec4b12b8 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x594daad7d77592a2b97b725a7ad59d7e188b5bfa + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x8355dbe8b0e275abad27eb843f3eaf3fc855e525 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x2a961d752eaa791cbff05991e4613290aec0d9ac + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x38e68a37e401f7271568cecaac63c6b1e19130b4 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x1131d427ecd794714ed00733ac0f851e904c8398 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x1495bc9e44af1f8bcb62278d2bec4540cf0c05ea + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x808507121b80c02388fad14726482e061b8da827 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x44971abf0251958492fee97da3e5c5ada88b9185 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x320623b8e4ff03373931769a31fc52a4e78b5d70 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x6e5970dbd6fc7eb1f29c6d2edf2bc4c36124c0c1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xd40c688da9df74e03566eaf0a7c754ed98fbb8cc + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x8afe4055ebc86bd2afb3940c0095c9aca511d852 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x9ce84f6a69986a83d92c324df10bc8e64771030f + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xbe4d9c8c638b5f0864017d7f6a04b66c42953847 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x68bbed6a47194eff1cf514b50ea91895597fc91e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x69420e3a3aa9e17dea102bb3a9b3b73dcddb9528 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x7420b4b9a0110cdc71fb720908340c03f9bc03ec + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x03aa6298f1370642642415edc0db8b957783e8d6 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xd533a949740bb3306d119cc777fa900ba034cd52 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xf14dd7b286ce197019cba54b189d2b883e70f761 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xa35923162c49cf95e6bf26623385eb431ad920d3 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x8cefbeb2172a9382753de431a493e21ba9694004 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x120a3879da835a5af037bb2d1456bebd6b54d4ba + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x69457a1c9ec492419344da01daf0df0e0369d5d0 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xf6ce4be313ead51511215f1874c898239a331e37 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x73d7c860998ca3c01ce8c808f5577d94d545d1b4 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xeff49b0f56a97c7fd3b51f0ecd2ce999a7861420 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x236501327e701692a281934230af0b6be8df3353 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x5026f006b85729a8b14553fae6af249ad16c9aab + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x66761fa41377003622aee3c7675fc7b5c1c2fac5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x9f9c8ec3534c3ce16f928381372bfbfbfb9f4d24 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xd8c978de79e12728e38aa952a6cb4166f891790f + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x7122985656e38bdc0302db86685bb972b145bd3c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x582d872a1b094fc48f5de31d3b73f2d9be47def1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x504624040e0642921c2c266a9ac37cafbd8cda4e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xc548e90589b166e1364de744e6d35d8748996fe8 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x4c11249814f11b9346808179cf06e71ac328c1b5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x423f4e6138e475d85cf7ea071ac92097ed631eea + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x8390a1da07e376ef7add4be859ba74fb83aa02d5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xf94e7d0710709388bce3161c32b4eea56d3f91cc + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xaa95f26e30001251fb905d264aa7b00ee9df6c18 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x2416092f143378750bb29b79ed961ab195cceea5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x6c84a8f1c29108f47a79964b5fe888d4f4d0de40 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x71eeba415a523f5c952cc2f06361d5443545ad28 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x88a269df8fe7f53e590c561954c52fccc8ec0cfb + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x429fed88f10285e61b12bdf00848315fbdfcc341 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xb299751b088336e165da313c33e3195b8c6663a6 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xf0a479c9c3378638ec603b8b6b0d75903902550b + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xb59c8912c83157a955f9d715e556257f432c35d7 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xba0dda8762c24da9487f5fa026a9b64b695a07ea + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xc24a365a870821eb83fd216c9596edd89479d8d7 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xa586b3b80d7e3e8d439e25fbc16bc5bcee3e2c85 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xef04804e1e474d3f9b73184d7ef5d786f3fce930 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x2e9a6df78e42a30712c10a9dc4b1c8656f8f2879 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x13a7dedb7169a17be92b0e3c7c2315b46f4772b3 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x1dd6b5f9281c6b4f043c02a83a46c2772024636c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xc5102fe9359fd9a28f877a67e36b0f050d81a3cc + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xf525e73bdeb4ac1b0e741af3ed8a8cbb43ab0756 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xe4177c1400a8eee1799835dcde2489c6f0d5d616 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xed5740209fcf6974d6f3a5f11e295b5e468ac27c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xe10d4a4255d2d35c9e23e2c4790e073046fbaf5c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/optimism/0x10398abc267496e49106b07dd6be13364d10dc71 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/optimism/0x2218a117083f5b482b0bb821d27056ba9c04b1d3 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/optimism/0x395ae52bb17aef68c2888d941736a71dc6d4e125 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/optimism/0x9a601c5bb360811d96a23689066af316a30c3027 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0xbac3368b5110f3a3dda8b5a0f7b66edb37c47afe + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x1d3c629ca5c1d0ab3bdf74600e81b4145615df8e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0xe9c21de62c5c5d0ceacce2762bf655afdceb7ab3 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x658cda444ac43b0a7da13d638700931319b64014 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x3d2bd0e15829aa5c362a4144fdf4a1112fa29b5c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x3fb83a9a2c4408909c058b0bfe5b4823f54fafe2 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x00e5646f60ac6fb446f621d146b6e1886f002905 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x12a4cebf81f8671faf1ab0acea4e3429e42869e7 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x9ff62d1fc52a907b6dcba8077c2ddca6e6a9d3e1 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0xc61f39418cd27820b5d4e9ba4a7197eefaeb8b05 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x15b7c0c907e4c6b9adaaaabc300c08991d6cea05 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x7f67639ffc8c93dd558d452b8920b28815638c44 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x276c9cbaa4bdf57d7109a41e67bd09699536fa3d + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x041fdf3f472d2c8a7ecc458fc3b7f543e6c57ef7 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x3c281a39944a2319aa653d81cfd93ca10983d234 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x96419929d7949d6a801a6909c145c8eef6a40431 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xfea9dcdc9e23a9068bf557ad5b186675c61d33ea + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xdb6e0e5094a25a052ab6845a9f1e486b9a9b3dde + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xcde172dc5ffc46d228838446c57c1227e0b82049 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xff0c532fdb8cd566ae169c1cb157ff2bdc83e105 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x9a26f5433671751c3276a065f57e5a02d2817973 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x3636a7734b669ce352e97780df361ce1f809c58c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x50c5725949a6f0c72e6c4a641f24049a917db0cb + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xe3086852a4b125803c815a158249ae468a3254ca + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xbeb0fd48c2ba0f1aacad2814605f09e08a96b94e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xbc45647ea894030a4e9801ec03479739fa2485f0 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x768be13e1680b5ebe0024c42c896e3db59ec0149 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x928a6a9fc62b2c94baf2992a6fba4715f5bb0066 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xbf4db8b7a679f89ef38125d5f84dd1446af2ea3b + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xed899bfdb28c8ad65307fa40f4acab113ae2e14c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x1b6a569dd61edce3c383f6d565e2f79ec3a12980 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x76734b57dfe834f102fb61e1ebf844adf8dd931e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x4621b7a9c75199271f773ebd9a499dbd165c3191 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xaf07d812d1dcec20bf741075bc18660738d226dd + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x7f12d13b34f5f4f0a9449c16bcd42f0da47af200 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x55a6f6cb50db03259f6ab17979a4891313be2f45 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x968d6a288d7b024d5012c0b25d67a889e4e3ec19 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x7a8a5012022bccbf3ea4b03cd2bb5583d915fb1a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xcde90558fc317c69580deeaf3efc509428df9080 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x0028e1e60167b48a938b785aa5292917e7eaca8b + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x76e7447bafa3f0acafc9692629b1d1bc937ca15d + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x15ac90165f8b45a80534228bdcb124a011f62fee + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x4045b33f339a3027af80013fb5451fdbb01a4492 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xddf98aad8180c3e368467782cd07ae2e3e8d36a5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x698dc45e4f10966f6d1d98e3bfd7071d8144c233 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x3c8665472ec5af30981b06b4e0143663ebedcc1e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x18a8bd1fe17a1bb9ffb39ecd83e9489cfd17a022 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xba0dda8762c24da9487f5fa026a9b64b695a07ea + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x13741c5df9ab03e7aa9fb3bf1f714551dd5a5f8a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xebff2db643cf955247339c8c6bcd8406308ca437 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xfadb26be94c1f959f900bf88cd396b3e803481d6 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x52c2b317eb0bb61e650683d2f287f56c413e4cf6 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x38d513ec43dda20f323f26c7bef74c5cf80b6477 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x33ad778e6c76237d843c52d7cafc972bb7cf8729 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x290814ad0fbd2b935f34d7b40306102313d4c63e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x5e432eecd01c12ee7071ee9219c2477a347da192 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xbdf5bafee1291eec45ae3aadac89be8152d4e673 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xff62ddfa80e513114c3a0bf4d6ffff1c1d17aadf + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x8c81b4c816d66d36c4bf348bdec01dbcbc70e987 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x6b82297c6f1f9c3b1f501450d2ee7c37667ab70d + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x42069babe14fb1802c5cb0f50bb9d2ad6fef55e2 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x72499bddb67f4ca150e1f522ca82c87bc9fb18c8 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x0578d8a44db98b23bf096a382e016e29a5ce0ffe + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x8fe815417913a93ea99049fc0718ee1647a2a07c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x7d12aeb5d96d221071d176980d23c213d88d9998 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xb166e8b140d35d9d8226e40c09f757bac5a4d87d + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x8853f0c059c27527d33d02378e5e4f6d5afb574a + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xf3c052f2baab885c610a748eb01dfbb643ba835b + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xcd1cffa8ebc66f1a2cf7675b48ba955ffcb82d8e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xde7a416ac821c77478340eebaa21b68297025ef3 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x2da56acb9ea78330f947bd57c54119debda7af71 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x8972ab69d499b5537a31576725f0af8f67203d38 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x88faea256f789f8dd50de54f9c807eef24f71b16 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x42069de48741db40aef864f8764432bbccbd0b69 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x9a27c6759a6de0f26ac41264f0856617dec6bc3f + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xfaa4f3bcfc87d791e9305951275e0f62a98bcb10 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xfd9fa4f785331ce88b5af8994a047ba087c705d8 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x21eceaf3bf88ef0797e3927d855ca5bb569a47fc + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x7d9ce55d54ff3feddb611fc63ff63ec01f26d15f + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x4229c271c19ca5f319fb67b4bc8a40761a6d6299 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x80f45eacf6537498ecc660e4e4a2d2f99e195cf4 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x1a475d06d967aeb686c98de80d079d72097aeacf + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x4fb9b20dafe45d91ae287f2e07b2e79709308178 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xd3741ac9b3f280b0819191e4b30be4ecd990771e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x09579452bc3872727a5d105f342645792bb8a82b + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x8a24d7260cd02d3dfd8eefb66bc17ad4b17d494c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xd88611a629265c9af294ffdd2e7fa4546612273e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x9a86980d3625b4a6e69d8a4606d51cbc019e2002 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x1c7a460413dd4e964f96d8dfc56e7223ce88cd85 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x776aaef8d8760129a0398cf8674ee28cefc0eab9 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x28e29ec91db66733a94ee8e3b86a6199117baf99 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xb9898511bd2bad8bfc23eba641ef97a08f27e730 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x76baa16ff15d61d32e6b3576c3a8c83a25c2f180 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x2816a491dd0b7a88d84cbded842a618e59016888 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xa7ea9d5d4d4c7cf7dbde5871e6d108603c6942a5 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x586e10db93630a4d2da6c6a34ba715305b556f04 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/bnb/0xf486ad071f3bee968384d2e39e2d8af0fcf6fd46 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/bnb/0x76d36d44dc4595e8d2eb3ad745f175eda134284f + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/bnb/0x1fa4a73a3f0133f0025378af00236f3abdee5d63 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/bnb/0xb3ed0a426155b79b898849803e3b36552f7ed507 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/bnb/0x0ef4a107b48163ab4b57fca36e1352151a587be4 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/bnb/0x62694d43ccb9b64e76e38385d15e325c7712a735 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/bnb/0xa2b726b1145a4773f68593cf171187d8ebe4d495 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/bnb/0xf275e1ac303a4c9d987a2c48b8e555a77fec3f1c + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/bnb/0x11a31b833d43853f8869c9eec17f60e3b4d2a753 + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/celo/0x48065fbbe25f71c9282ddf5e1cd6d6a887483d5e + 2024-05-20T17:20:52.753Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xbadff0ef41d2a68f22de21eabca8a59aaf495cf0 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x1fdd61ef9a5c31b9a2abc7d39c139c779e8412af + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x4ade2b180f65ed752b6f1296d0418ad21eb578c0 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x0c5cb676e38d6973837b9496f6524835208145a2 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xb69753c06bb5c366be51e73bfc0cc2e3dc07e371 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x8143182a775c54578c8b7b3ef77982498866945d + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x76e222b07c53d28b89b0bac18602810fc22b49a8 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x18aaa7115705e8be94bffebde57af9bfc265b998 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x7d8146cf21e8d7cbe46054e01588207b51198729 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xfe0c30065b384f05761f15d0cc899d4f9f9cc0eb + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x1ce270557c1f68cfb577b856766310bf8b47fd9c + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x793a5d8b30aab326f83d20a9370c827fea8fdc51 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xff836a5821e69066c87e268bc51b849fab94240c + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xf4d2888d29d722226fafa5d9b24f9164c092421e + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x8ed97a637a790be1feff5e888d43629dc05408f6 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x31c8eacbffdd875c74b94b077895bd78cf1e64a3 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xc55126051b22ebb829d00368f4b12bde432de5da + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xe0f63a424a4439cbe457d80e4f4b51ad25b2c56c + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x8881562783028f5c1bcb985d2283d5e170d88888 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x67466be17df832165f8c80a5a120ccc652bd7e69 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xd939212f16560447ed82ce46ca40a63db62419b5 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x88417754ff7062c10f4e3a4ab7e9f9d9cbda6023 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x5afe3855358e112b5647b952709e6165e1c1eeee + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x02e7f808990638e9e67e1f00313037ede2362361 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xd2bdaaf2b9cc6981fd273dcb7c04023bfbe0a7fe + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x112b08621e27e10773ec95d250604a041f36c582 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x32b053f2cba79f80ada5078cb6b305da92bde6e1 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x5ac34c53a04b9aaa0bf047e7291fb4e8a48f2a18 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x26ebb8213fb8d66156f1af8908d43f7e3e367c1d + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0xe3b9cfb8ea8a4f1279fbc28d3e15b4d2d86f18a0 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x8207c1ffc5b6804f6024322ccf34f29c3541ae26 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/ethereum/0x255f1b39172f65dc6406b8bee8b08155c45fe1b6 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x092baadb7def4c3981454dd9c0a0d7ff07bcfc86 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x53bcf6698c911b2a7409a740eacddb901fc2a2c6 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x2ac2b254bc18cd4999f64773a966e4f4869c34ee + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x17fc002b466eec40dae837fc4be5c67993ddbd6f + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xc8a4eea31e9b6b61c406df013dd4fec76f21e279 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x498bf2b1e120fed3ad3d42ea2165e9b73f99c1e5 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xe4dddfe67e7164b0fe14e218d80dc4c08edc01cb + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x7c8a1a80fdd00c9cccd6ebd573e9ecb49bfa2a59 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0x1debd73e752beaf79865fd6446b0c970eae7732f + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/arbitrum/0xaf5db6e1cc585ca312e8c8f7c499033590cf5c98 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/optimism/0x65559aa14915a70190438ef90104769e5e890a00 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/optimism/0x7fb688ccf682d58f86d7e38e03f9d22e7705448b + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/optimism/0x73cb180bf0521828d8849bc8cf2b920918e23032 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/optimism/0x2e3d870790dc77a83dd1d18184acc7439a53f475 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/optimism/0xa00e3a3511aac35ca78530c85007afcd31753819 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/optimism/0x528cdc92eab044e1e39fe43b9514bfdab4412b98 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/optimism/0x4f604735c1cf31399c6e711d5962b2b3e0225ad3 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x1c954e8fe737f99f68fa1ccda3e51ebdb291948c + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0xf50d05a1402d0adafa880d36050736f9f6ee7dee + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0xab0b2ddb9c7e440fac8e140a89c0dbcbf2d7bbff + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x8bc3ec2e7973e64be582a90b08cadd13457160fe + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x64060ab139feaae7f06ca4e63189d86adeb51691 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x5ec03c1f7fa7ff05ec476d19e34a22eddb48acdc + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x9627a3d6872be48410fcece9b1ddd344bf08c53e + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/polygon/0x1ed02954d60ba14e26c230eec40cbac55fa3aeea + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x8d3419b9a18651f3926a205ee0b1acea1e7192de + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xb56d0839998fd79efcd15c27cf966250aa58d6d3 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x81f91fe59ee415735d59bd5be5cca91a0ea4fa69 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x87c211144b1d9bdaa5a791b8099ea4123dc31d21 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xf4210f93bc68d63df3286c73eba08c6414f40c0d + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xece7b98bd817ee5b1f2f536daf34d0b6af8bb542 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x4c96a67b0577358894407af7bc3158fc1dffbeb5 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x70737489dfdf1a29b7584d40500d3561bd4fe196 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x39353a32eceafe4979a8606512c046c3b6398cc4 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x92fb1b7d9730b2f1bd4e2e91368c1eb6fdd2a009 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x174e33ef2effa0a4893d97dda5db4044cc7993a3 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xfdc944fb59201fb163596ee5e209ebc8fa4dcdc5 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x388e543a5a491e7b42e3fbcd127dd6812ea02d0d + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x56a38e7216304108e841579041249feb236c887b + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x1804e3db872eed4141e482ff74c56862f2791103 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x9de16c805a3227b9b92e39a446f9d56cf59fe640 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xb8d98a102b0079b69ffbc760c8d857a31653e56e + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x5d6812722c3693078e4a0dbe3e9affc27a0b2768 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x255f1b39172f65dc6406b8bee8b08155c45fe1b6 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xc2fe011c3885277c7f0e7ffd45ff90cadc8ecd12 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xc1ffaef4e7d553bbaf13926e258a1a555a363a07 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0x4e73420dcc85702ea134d91a262c8ffc0a72aa70 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/base/0xecaf81eb42cd30014eb44130b89bcd6d4ad98b92 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/bnb/0x4eae52907dba9c370e9ee99f0ce810602a4f2c63 + 2024-05-24T23:13:47.908Z + 0.8 + + + https://app.uniswap.org/explore/tokens/bnb/0x25d887ce7a35172c62febfd67a1856f20faebb00 + 2024-05-24T23:13:47.908Z 0.8 \ No newline at end of file diff --git a/apps/web/scripts/generate-sitemap.js b/apps/web/scripts/generate-sitemap.js index 14dad6fb0e9..42a38bdb135 100644 --- a/apps/web/scripts/generate-sitemap.js +++ b/apps/web/scripts/generate-sitemap.js @@ -83,7 +83,9 @@ fs.readFile('./public/tokens-sitemap.xml', 'utf8', async (err, data) => { const xml = builder.buildObject(sitemap) const path = './public/tokens-sitemap.xml' fs.writeFile(path, xml, (error) => { - if (error) throw error + if (error) { + throw error + } const stats = fs.statSync(path) const fileSizeBytes = stats.size const fileSizeMegabytes = fileSizeBytes / (1024 * 1024) @@ -137,7 +139,9 @@ fs.readFile('./public/nfts-sitemap.xml', 'utf8', async (err, data) => { const xml = builder.buildObject(sitemap) const path = './public/nfts-sitemap.xml' fs.writeFile(path, xml, (error) => { - if (error) throw error + if (error) { + throw error + } const stats = fs.statSync(path) const fileSizeBytes = stats.size const fileSizeMegabytes = fileSizeBytes / (1024 * 1024) @@ -196,7 +200,9 @@ fs.readFile('./public/pools-sitemap.xml', 'utf8', async (err, data) => { const xml = builder.buildObject(sitemap) const path = './public/pools-sitemap.xml' fs.writeFile(path, xml, (error) => { - if (error) throw error + if (error) { + throw error + } const stats = fs.statSync(path) const fileSizeBytes = stats.size const fileSizeMegabytes = fileSizeBytes / (1024 * 1024) diff --git a/apps/web/src/analytics/index.tsx b/apps/web/src/analytics/index.tsx deleted file mode 100644 index bc9c0bd8bc2..00000000000 --- a/apps/web/src/analytics/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { - TraceEvent as AnalyticsEvent, - Trace as AnalyticsTrace, - sendAnalyticsEvent as sendAnalyticsTraceEvent, -} from '@uniswap/analytics' -import { atomWithStorage, useAtomValue } from 'jotai/utils' -import { memo } from 'react' - -export { - OriginApplication, - getDeviceId, - initializeAnalytics, - useTrace, - user, - type ITraceContext, -} from '@uniswap/analytics' - -const allowAnalyticsAtomKey = 'allow_analytics' -export const allowAnalyticsAtom = atomWithStorage(allowAnalyticsAtomKey, true) - -export const Trace = memo((props: React.ComponentProps) => { - const allowAnalytics = useAtomValue(allowAnalyticsAtom) - const shouldLogImpression = allowAnalytics ? props.shouldLogImpression : false - - return -}) - -Trace.displayName = 'Trace' - -export const TraceEvent = memo((props: React.ComponentProps) => { - const allowAnalytics = useAtomValue(allowAnalyticsAtom) - const shouldLogImpression = allowAnalytics ? props.shouldLogImpression : false - - return -}) - -TraceEvent.displayName = 'TraceEvent' - -export const sendAnalyticsEvent: typeof sendAnalyticsTraceEvent = (event, properties) => { - let allowAnalytics = true - - try { - const value = localStorage.getItem(allowAnalyticsAtomKey) - - if (typeof value === 'string') { - allowAnalytics = JSON.parse(value) - } - // eslint-disable-next-line no-empty - } catch {} - - if (allowAnalytics) { - sendAnalyticsTraceEvent(event, properties) - } -} - -// This is only used for initial page load so we can get the user's country -export const sendInitializationEvent: typeof sendAnalyticsTraceEvent = (event, properties) => { - sendAnalyticsTraceEvent(event, properties) -} diff --git a/apps/web/src/components/AccountDetails/TransactionSummary.tsx b/apps/web/src/components/AccountDetails/TransactionSummary.tsx index 17cc75161d9..0c3205d22db 100644 --- a/apps/web/src/components/AccountDetails/TransactionSummary.tsx +++ b/apps/web/src/components/AccountDetails/TransactionSummary.tsx @@ -74,25 +74,31 @@ function ClaimSummary({ info: { recipient, uniAmountRaw } }: { info: ClaimTransa const { ENSName } = useENSName() const name = ENSName ?? recipient return typeof uniAmountRaw === 'string' ? ( - - Claim for {{ name }} - + , + }} + values={{ + name, + }} + /> ) : ( - Claim UNI reward for {{ name }} + ) } function SubmitProposalTransactionSummary() { - return Submit new proposal + return } function ApprovalSummary({ info }: { info: ApproveTransactionInfo }) { const token = useToken(info.tokenAddress) return BigNumber.from(info.amount)?.eq(0) ? ( - Revoke {{ sym: token?.symbol }} + ) : ( - Approve {{ sym: token?.symbol }} + ) } @@ -101,31 +107,23 @@ function VoteSummary({ info }: { info: VoteTransactionInfo }) { if (info.reason && info.reason.trim().length > 0) { switch (info.decision) { case VoteOption.For: - return Vote for proposal {{ proposalKey }} + return case VoteOption.Abstain: - return Vote to abstain on proposal {{ proposalKey }} + return case VoteOption.Against: - return Vote against proposal {{ proposalKey }} + return } } else { switch (info.decision) { case VoteOption.For: - return ( - - Vote for proposal {{ proposalKey }} with reason "{{ reason: info.reason }}" - - ) + return case VoteOption.Abstain: return ( - - Vote to abstain on proposal {{ proposalKey }} with reason "{{ reason: info.reason }}" - + ) case VoteOption.Against: return ( - - Vote against proposal {{ proposalKey }} with reason "{{ reason: info.reason }}" - + ) } } @@ -133,18 +131,18 @@ function VoteSummary({ info }: { info: VoteTransactionInfo }) { function QueueSummary({ info }: { info: QueueTransactionInfo }) { const proposalKey = `${info.governorAddress}/${info.proposalId}` - return Queue proposal {{ proposalKey }}. + return } function ExecuteSummary({ info }: { info: ExecuteTransactionInfo }) { const proposalKey = `${info.governorAddress}/${info.proposalId}` - return Execute proposal {{ proposalKey }}. + return } function DelegateSummary({ info: { delegatee } }: { info: DelegateTransactionInfo }) { const { ENSName } = useENSName(delegatee) const name = ENSName ?? delegatee - return Delegate voting power to {{ name }} + return } function WrapSummary({ info: { chainId, currencyAmountRaw, unwrapped } }: { info: WrapTransactionInfo }) { @@ -152,29 +150,41 @@ function WrapSummary({ info: { chainId, currencyAmountRaw, unwrapped } }: { info if (unwrapped) { return ( - - Unwrap{' '} - {' '} - to {{ symbol: native?.symbol ?? 'ETH' }} - + + ), + }} + values={{ + symbol: native?.symbol ?? 'ETH', + }} + /> ) } else { return ( - - Wrap{' '} - {' '} - to {{ symbol: native?.wrapped?.symbol ?? 'WETH' }} - + + ), + }} + values={{ + symbol: native?.wrapped?.symbol ?? 'WETH', + }} + /> ) } } @@ -182,11 +192,11 @@ function WrapSummary({ info: { chainId, currencyAmountRaw, unwrapped } }: { info function DepositLiquidityStakingSummary() { // not worth rendering the tokens since you can should no longer deposit liquidity in the staking contracts // todo: deprecate and delete the code paths that allow this, show user more information - return Deposit liquidity + return } function WithdrawLiquidityStakingSummary() { - return Withdraw deposited liquidity + return } function MigrateLiquidityToV3Summary({ @@ -198,9 +208,13 @@ function MigrateLiquidityToV3Summary({ const quoteCurrency = useCurrency(quoteCurrencyId) return ( - - Migrate {{ baseSymbol: baseCurrency?.symbol }}/{{ quoteSymbol: quoteCurrency?.symbol }} liquidity to V3 - + ) } @@ -209,9 +223,13 @@ function CreateV3PoolSummary({ info: { quoteCurrencyId, baseCurrencyId } }: { in const quoteCurrency = useCurrency(quoteCurrencyId) return ( - - Create {{ baseSymbol: baseCurrency?.symbol }}/{{ quoteSymbol: quoteCurrency?.symbol }} V3 pool - + ) } @@ -220,9 +238,13 @@ function CollectFeesSummary({ info: { currencyId0, currencyId1 } }: { info: Coll const currency1 = useCurrency(currencyId1) return ( - - Collect {{ symbol0: currency0?.symbol }}/{{ symbol1: currency1?.symbol }} fees - + ) } @@ -232,11 +254,17 @@ function RemoveLiquidityV3Summary({ info: RemoveLiquidityV3TransactionInfo }) { return ( - - Remove{' '} - and{' '} - - + + ), + quote: ( + + ), + }} + /> ) } @@ -249,13 +277,21 @@ function AddLiquidityV3PoolSummary({ const quoteCurrency = useCurrency(quoteCurrencyId) return createPool ? ( - - Create pool and add {{ baseSymbol: baseCurrency?.symbol }}/{{ quoteSymbol: quoteCurrency?.symbol }} V3 liquidity - + ) : ( - - Add {{ baseSymbol: baseCurrency?.symbol }}/{{ quoteSymbol: quoteCurrency?.symbol }} V3 liquidity - + ) } @@ -265,62 +301,81 @@ function AddLiquidityV2PoolSummary({ info: AddLiquidityV2PoolTransactionInfo }) { return ( - - Add {' '} - and {' '} - to Uniswap V2 - + + ), + quote: ( + + ), + }} + /> ) } function SendSummary({ info }: { info: SendTransactionInfo }) { return ( - - Sent - to{' '} - {{ recipient: info.recipient }} - + , + }} + values={{ + recipient: info.recipient, + }} + /> ) } function SwapSummary({ info }: { info: ExactInputSwapTransactionInfo | ExactOutputSwapTransactionInfo }) { if (info.tradeType === TradeType.EXACT_INPUT) { return ( - - Swap exactly{' '} - {' '} - for{' '} - - + + ), + amount2: ( + + ), + }} + /> ) } else { return ( - - Swap{' '} - {' '} - for exactly{' '} - - + + ), + amount2: ( + + ), + }} + /> ) } } - export function TransactionSummary({ info }: { info: TransactionInfo }) { switch (info.type) { case TransactionType.ADD_LIQUIDITY_V3_POOL: diff --git a/apps/web/src/components/AccountDrawer/AnalyticsToggle.tsx b/apps/web/src/components/AccountDrawer/AnalyticsToggle.tsx index baa42a0982c..e817b6dc731 100644 --- a/apps/web/src/components/AccountDrawer/AnalyticsToggle.tsx +++ b/apps/web/src/components/AccountDrawer/AnalyticsToggle.tsx @@ -1,18 +1,25 @@ -import { allowAnalyticsAtom } from 'analytics' import { t } from 'i18n' -import { useAtom } from 'jotai' - +import { useState } from 'react' +// eslint-disable-next-line @typescript-eslint/no-restricted-imports +import { analytics, getAnalyticsAtomDirect } from 'utilities/src/telemetry/analytics/analytics' import { SettingsToggle } from './SettingsToggle' export function AnalyticsToggle() { - const [allowAnalytics, updateAllowAnalytics] = useAtom(allowAnalyticsAtom) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [x, setCounter] = useState(0) + const [allowAnalytics, setAllowAnalytics] = useState(true) + + getAnalyticsAtomDirect(true).then((v: boolean) => setAllowAnalytics(v)) return ( void updateAllowAnalytics((value) => !value)} + toggle={() => { + analytics.setAllowAnalytics(!allowAnalytics) + setCounter((c) => c + 1) + }} /> ) } diff --git a/apps/web/src/components/AccountDrawer/AuthenticatedHeader.tsx b/apps/web/src/components/AccountDrawer/AuthenticatedHeader.tsx index d16b062e7c0..d1340fb6c5b 100644 --- a/apps/web/src/components/AccountDrawer/AuthenticatedHeader.tsx +++ b/apps/web/src/components/AccountDrawer/AuthenticatedHeader.tsx @@ -1,6 +1,5 @@ -import { BrowserEvent, InterfaceElementName, InterfaceEventName, SharedEventName } from '@uniswap/analytics-events' +import { InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' import { CurrencyAmount, Token } from '@uniswap/sdk-core' -import { TraceEvent, sendAnalyticsEvent } from 'analytics' import { ButtonEmphasis, ButtonSize, ThemeButton } from 'components/Button' import Column from 'components/Column' import { CreditCardIcon } from 'components/Icons/CreditCard' @@ -20,6 +19,8 @@ import { useCallback, useState } from 'react' import { useNavigate } from 'react-router-dom' import styled from 'styled-components' import { ThemedText } from 'theme/components' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { useUnitagByAddress } from 'uniswap/src/features/unitags/hooks' import { isPathBlocked } from 'utils/blockedPaths' import { NumberType, useFormatter } from 'utils/formatNumbers' @@ -167,11 +168,7 @@ export default function AuthenticatedHeader({ account, openSettings }: { account onClick={openSettings} Icon={Settings} /> - + - + @@ -217,20 +214,20 @@ export default function AuthenticatedHeader({ account, openSettings }: { account } - name={t`Buy`} + name={t('common.buy.label')} onClick={handleBuyCryptoClick} disabled={disableBuyCryptoButton} loading={fiatOnrampAvailabilityLoading} error={Boolean(!fiatOnrampAvailable && fiatOnrampAvailabilityChecked)} - errorMessage={t`Restricted region`} - errorTooltip={t`Moonpay is not available in some regions. Click to learn more.`} + errorMessage={t('common.restricted.region')} + errorTooltip={t('moonpay.restricted.region')} /> )} {!shouldDisableNFTRoutes && ( } - name={t`View NFTs`} + name={t('nft.view')} onClick={navigateToProfile} /> )} @@ -238,7 +235,7 @@ export default function AuthenticatedHeader({ account, openSettings }: { account {isUnclaimed && ( - Claim {{ amount }} reward + )} diff --git a/apps/web/src/components/AccountDrawer/DefaultMenu.tsx b/apps/web/src/components/AccountDrawer/DefaultMenu.tsx index 8dc404b1ac7..6f3ec84d9ce 100644 --- a/apps/web/src/components/AccountDrawer/DefaultMenu.tsx +++ b/apps/web/src/components/AccountDrawer/DefaultMenu.tsx @@ -2,11 +2,11 @@ import { useWeb3React } from '@web3-react/core' import { LimitsMenu } from 'components/AccountDrawer/MiniPortfolio/Limits/LimitsMenu' import Column from 'components/Column' import WalletModal from 'components/WalletModal' +import { atom, useAtom } from 'jotai' import { useCallback, useEffect, useMemo } from 'react' import styled from 'styled-components' - -import { sendAnalyticsEvent } from 'analytics' -import { atom, useAtom } from 'jotai' +import { InterfaceEventNameLocal } from 'uniswap/src/features/telemetry/constants' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import AuthenticatedHeader from './AuthenticatedHeader' import LanguageMenu from './LanguageMenu' import LocalCurrencyMenu from './LocalCurrencyMenu' @@ -50,9 +50,11 @@ function DefaultMenu({ drawerOpen }: { drawerOpen: boolean }) { }, [drawerOpen, menu, closeSettings]) useEffect(() => { - if (menu === MenuState.DEFAULT) return // menu is closed, don't log + if (menu === MenuState.DEFAULT) { + return + } // menu is closed, don't log - sendAnalyticsEvent('Portfolio Menu Opened', { name: menu }) + sendAnalyticsEvent(InterfaceEventNameLocal.PortfolioMenuOpened, { name: menu }) }, [menu]) const SubMenu = useMemo(() => { diff --git a/apps/web/src/components/AccountDrawer/GitVersionRow.tsx b/apps/web/src/components/AccountDrawer/GitVersionRow.tsx index 50d99935cb3..be76d36c588 100644 --- a/apps/web/src/components/AccountDrawer/GitVersionRow.tsx +++ b/apps/web/src/components/AccountDrawer/GitVersionRow.tsx @@ -19,7 +19,7 @@ export function GitVersionRow() { > - Version: + {' ' + process.env.REACT_APP_GIT_COMMIT_HASH.substring(0, 6)} diff --git a/apps/web/src/components/AccountDrawer/IconButton.tsx b/apps/web/src/components/AccountDrawer/IconButton.tsx index 86c7dc85042..a7edf39e63d 100644 --- a/apps/web/src/components/AccountDrawer/IconButton.tsx +++ b/apps/web/src/components/AccountDrawer/IconButton.tsx @@ -164,8 +164,12 @@ export const IconWithConfirmTextButton = ({ // keyboard action to cancel useEffect(() => { - if (typeof window === 'undefined') return - if (!showText || !frame) return + if (typeof window === 'undefined') { + return + } + if (!showText || !frame) { + return + } const closeAndPrevent = (e: Event) => { setShowText(false) diff --git a/apps/web/src/components/AccountDrawer/LanguageMenu.tsx b/apps/web/src/components/AccountDrawer/LanguageMenu.tsx index 70a31780c9d..ae31fea12ad 100644 --- a/apps/web/src/components/AccountDrawer/LanguageMenu.tsx +++ b/apps/web/src/components/AccountDrawer/LanguageMenu.tsx @@ -39,7 +39,7 @@ export function LanguageMenuItems() { export default function LanguageMenu({ onClose }: { onClose: () => void }) { return ( - Language} onClose={onClose}> + } onClose={onClose}> diff --git a/apps/web/src/components/AccountDrawer/LocalCurrencyMenu.tsx b/apps/web/src/components/AccountDrawer/LocalCurrencyMenu.tsx index 1512b3f0921..04df38105f6 100644 --- a/apps/web/src/components/AccountDrawer/LocalCurrencyMenu.tsx +++ b/apps/web/src/components/AccountDrawer/LocalCurrencyMenu.tsx @@ -28,7 +28,9 @@ function LocalCurrencyMenuItem({ return {getLocalCurrencyIcon(localCurrency)} }, [localCurrency]) - if (!to) return null + if (!to) { + return null + } return ( void }) const activeLocalCurrency = useActiveLocalCurrency() return ( - Currency} onClose={onClose}> + } onClose={onClose}> {SUPPORTED_LOCAL_CURRENCIES.map((localCurrency) => ( case TransactionStatus.Confirmed: return {timeSince} @@ -66,9 +67,8 @@ export function ActivityRow({ activity }: { activity: Activity }) { }, [activity?.logos, chainId, hash, offchainOrderDetails, openOffchainActivityModal]) return ( - @@ -93,6 +93,6 @@ export function ActivityRow({ activity }: { activity: Activity }) { right={} onClick={onClick} /> - + ) } diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/CancelLimitsDialog.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/CancelLimitsDialog.tsx index 85470c5d4c3..b96ce470072 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/CancelLimitsDialog.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/CancelLimitsDialog.tsx @@ -46,25 +46,25 @@ function useCancelLimitsDialogContent( title: ( ), icon: , } case CancellationState.PENDING_SIGNATURE: return { - title: Confirm cancellation, + title: , icon: , } case CancellationState.PENDING_CONFIRMATION: return { - title: Cancellation submitted, + title: , icon: , } case CancellationState.CANCELLED: return { - title: Cancellation Successful, + title: , icon: , } default: @@ -114,11 +114,11 @@ export function CancelLimitsDialog( href={getExplorerLink(orders[0].chainId, cancelTxHash, ExplorerDataType.TRANSACTION)} color="neutral2" > - View on Explorer + ) : ( - Proceed in your wallet + )} @@ -135,20 +135,20 @@ export function CancelLimitsDialog( } buttonsConfig={{ left: { - title: Nevermind, + title: , onClick: onCancel, textColor: 'neutral1', }, right: { - title: Proceed, + title: , onClick: onConfirm, type: DialogButtonType.Error, disabled: cancelState !== CancellationState.REVIEWING_CANCELLATION, @@ -175,7 +175,7 @@ function GasEstimateDisplay({ gasEstimateValue, chainId }: { gasEstimateValue?: Network cost, + Label: () => , Value: () => {gasEstimateValue ? gasFeeFormatted : '-'}, }} /> diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/OffchainActivityModal.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/OffchainActivityModal.tsx index b37b4956d61..f36245f6349 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/OffchainActivityModal.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/OffchainActivityModal.tsx @@ -3,12 +3,15 @@ import { CancelLimitsDialog, CancellationState, } from 'components/AccountDrawer/MiniPortfolio/Activity/CancelLimitsDialog' +import { useCancelMultipleOrdersCallback } from 'components/AccountDrawer/MiniPortfolio/Activity/utils' import { formatTimestamp } from 'components/AccountDrawer/MiniPortfolio/formatTimestamp' import { ButtonEmphasis, ButtonSize, ThemeButton } from 'components/Button' import Column, { AutoColumn } from 'components/Column' import { OpacityHoverState } from 'components/Common' +import AlertTriangleFilled from 'components/Icons/AlertTriangleFilled' import Modal from 'components/Modal' import Row from 'components/Row' +import { LimitDisclaimer } from 'components/swap/LimitDisclaimer' import { SwapModalHeaderAmount } from 'components/swap/SwapModalHeaderAmount' import { Field } from 'components/swap/constants' import { useCurrency } from 'hooks/Tokens' @@ -23,12 +26,9 @@ import { SignatureType, UniswapXOrderDetails } from 'state/signatures/types' import styled, { useTheme } from 'styled-components' import { Divider, ThemedText } from 'theme/components' import { UniswapXOrderStatus } from 'types/uniswapx' +import { InterfaceEventNameLocal } from 'uniswap/src/features/telemetry/constants' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink' - -import { sendAnalyticsEvent } from 'analytics' -import { useCancelMultipleOrdersCallback } from 'components/AccountDrawer/MiniPortfolio/Activity/utils' -import AlertTriangleFilled from 'components/Icons/AlertTriangleFilled' -import { LimitDisclaimer } from 'components/swap/LimitDisclaimer' import { PortfolioLogo } from '../PortfolioLogo' import { OffchainOrderLineItem, OffchainOrderLineItemProps, OffchainOrderLineItemType } from './OffchainOrderLineItem' @@ -50,7 +50,7 @@ export function useOpenOffchainActivityModal() { return useCallback( (order: UniswapXOrderDetails, logos?: Logos) => { - sendAnalyticsEvent('UniswapX Order Details Sheet Opened', { + sendAnalyticsEvent(InterfaceEventNameLocal.UniswapXOrderDetailsSheetOpened, { order: order.orderHash, }) setSelectedOrder({ order, logos, modalOpen: true }) @@ -112,7 +112,9 @@ export function useOrderAmounts(order?: UniswapXOrderDetails): const inputCurrency = useCurrency(order?.swapInfo?.inputCurrencyId || 'ETH', order?.chainId) const outputCurrency = useCurrency(order?.swapInfo?.outputCurrencyId || 'ETH', order?.chainId) - if (!order || !order?.swapInfo) return undefined + if (!order || !order?.swapInfo) { + return undefined + } if (!inputCurrency || !outputCurrency) { console.error(`Could not find token(s) for order ${order.txHash}`) @@ -141,17 +143,17 @@ function getOrderTitle(order: UniswapXOrderDetails): ReactNode { const isLimit = order.type === SignatureType.SIGN_LIMIT switch (order.status) { case UniswapXOrderStatus.OPEN: - return isLimit ? Limit pending : Order pending + return isLimit ? : case UniswapXOrderStatus.EXPIRED: - return isLimit ? Limit expired : Order expired + return isLimit ? : case UniswapXOrderStatus.PENDING_CANCELLATION: - return Pending cancellation + return case UniswapXOrderStatus.INSUFFICIENT_FUNDS: - return Insufficient funds + return case UniswapXOrderStatus.CANCELLED: - return isLimit ? Limit cancelled : Order cancelled + return isLimit ? : case UniswapXOrderStatus.FILLED: - return isLimit ? Limit executed : Order executed + return isLimit ? : default: return null } @@ -255,7 +257,11 @@ export function OrderContent({ {Boolean(order.status === UniswapXOrderStatus.OPEN && order.encodedOrder) && ( - {order.type === SignatureType.SIGN_LIMIT ? Cancel limit : Cancel order} + {order.type === SignatureType.SIGN_LIMIT ? ( + + ) : ( + + )} )} {order.status === UniswapXOrderStatus.INSUFFICIENT_FUNDS ? ( @@ -265,16 +271,13 @@ export function OrderContent({ - Insufficient balance + {order.type === SignatureType.SIGN_LIMIT ? ( - - This order will not fill because your balance went below the input amount. Increase your balance to - fix. - + ) : ( - This order was canceled because your balance went below the input amount. + )} @@ -292,7 +295,9 @@ function useSyncedSelectedOrder(): UniswapXOrderDetails | undefined { const localPendingOrder = useOrder(selectedOrder?.order?.orderHash ?? '') return useMemo(() => { - if (!selectedOrder?.order) return undefined + if (!selectedOrder?.order) { + return undefined + } if (selectedOrder.order.status === UniswapXOrderStatus.FILLED) { return selectedOrder.order @@ -373,7 +378,7 @@ export function OffchainActivityModal() { - Transaction details + diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/OffchainOrderLineItem.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/OffchainOrderLineItem.tsx index 8b1a4761e5d..f32a8a0631e 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/OffchainOrderLineItem.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/OffchainOrderLineItem.tsx @@ -42,7 +42,7 @@ function useLineItem(details: OffchainOrderLineItemProps): LineItemData | undefi switch (details.type) { case OffchainOrderLineItemType.EXCHANGE_RATE: return { - Label: () => Rate, + Label: () => Rate, Value: () => ( Expiry, + Label: () => , Value: () => {details.order.expiry && formatTimestamp(details.order.expiry * 1000)}, } case OffchainOrderLineItemType.NETWORK_COST: return { - Label: () => Network cost, + Label: () => , Value: () => {formatNumber({ input: 0, type: NumberType.FiatGasPrice })}, } case OffchainOrderLineItemType.TRANSACTION_ID: return { - Label: () => Transaction ID, + Label: () => , Value: () => ( {ellipseMiddle(details.order.txHash ?? '')} ), @@ -80,7 +80,9 @@ function useLineItem(details: OffchainOrderLineItemProps): LineItemData | undefi export function OffchainOrderLineItem(props: OffchainOrderLineItemProps) { const LineItem = useLineItem(props) - if (!LineItem) return null + if (!LineItem) { + return null + } return } diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/__snapshots__/OffchainActivityModal.test.tsx.snap b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/__snapshots__/OffchainActivityModal.test.tsx.snap index 36c5ab527c7..65c13ccef13 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/__snapshots__/OffchainActivityModal.test.tsx.snap +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/__snapshots__/OffchainActivityModal.test.tsx.snap @@ -800,6 +800,17 @@ exports[`OrderContent should render without error, limit order 1`] = ` overflow-wrap: break-word; } +.c27 { + background-color: #F9F9F9; + border-radius: 12px; + padding: 12px; + margin-top: 12px; +} + +.c28 { + line-height: 16px; +} + .c15 { display: -webkit-box; display: -webkit-flex; @@ -878,17 +889,6 @@ exports[`OrderContent should render without error, limit order 1`] = ` display: flex; } -.c27 { - background-color: #F9F9F9; - border-radius: 12px; - padding: 12px; - margin-top: 12px; -} - -.c28 { - line-height: 16px; -} - .c22 { background-color: transparent; border: none; diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/hooks.ts b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/hooks.ts index a6b26ac3c70..9d3b5d6e73b 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/hooks.ts +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/hooks.ts @@ -13,10 +13,14 @@ import { Activity, ActivityMap } from './types' /** Detects transactions from same account with the same nonce and different hash */ function findCancelTx(localActivity: Activity, remoteMap: ActivityMap, account: string): string | undefined { // handles locally cached tx's that were stored before we started tracking nonces - if (!localActivity.nonce || localActivity.status !== TransactionStatus.Pending) return undefined + if (!localActivity.nonce || localActivity.status !== TransactionStatus.Pending) { + return undefined + } for (const remoteTx of Object.values(remoteMap)) { - if (!remoteTx) continue + if (!remoteTx) { + continue + } // A pending tx is 'cancelled' when another tx with the same account & nonce but different hash makes it on chain if ( @@ -70,14 +74,20 @@ export function useAllActivities(account: string) { /* Updates locally stored pendings tx's when remote data contains a conflicting cancellation tx */ useEffect(() => { - if (!remoteMap) return + if (!remoteMap) { + return + } Object.values(localMap).forEach((localActivity) => { - if (!localActivity) return + if (!localActivity) { + return + } const cancelHash = findCancelTx(localActivity, remoteMap, account) - if (cancelHash) updateCancelledTx(localActivity.hash, localActivity.chainId, cancelHash) + if (cancelHash) { + updateCancelledTx(localActivity.hash, localActivity.chainId, cancelHash) + } }) }, [account, localMap, remoteMap, updateCancelledTx]) diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/parseLocal.ts b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/parseLocal.ts index 81f9db876eb..bd6750d5130 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/parseLocal.ts +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/parseLocal.ts @@ -39,21 +39,21 @@ function buildCurrencyDescriptor( currencyB: Currency | undefined, amtB: string, formatNumber: FormatNumberFunctionType, - delimiter = t`for` + delimiter = t('for') ) { const formattedA = currencyA ? formatNumber({ input: parseFloat(CurrencyAmount.fromRawAmount(currencyA, amtA).toSignificant()), type: NumberType.TokenNonTx, }) - : t`Unknown` + : t('common.unknown') const symbolA = currencyA?.symbol ?? '' const formattedB = currencyB ? formatNumber({ input: parseFloat(CurrencyAmount.fromRawAmount(currencyB, amtB).toSignificant()), type: NumberType.TokenNonTx, }) - : t`Unknown` + : t('common.unknown') const symbolB = currencyB?.symbol ?? '' return [formattedA, symbolA, delimiter, formattedB, symbolB].filter(Boolean).join(' ') } @@ -108,7 +108,7 @@ async function parseApproval( status: TransactionStatus ): Promise> { const currency = await getCurrency(approval.tokenAddress, chainId) - const descriptor = currency?.symbol ?? currency?.name ?? t`Unknown` + const descriptor = currency?.symbol ?? currency?.name ?? t('common.unknown') return { title: getActivityTitle( TransactionType.APPROVAL, @@ -134,7 +134,14 @@ async function parseLP( getCurrency(lp.quoteCurrencyId, chainId), ]) const [baseRaw, quoteRaw] = [lp.expectedAmountBaseRaw, lp.expectedAmountQuoteRaw] - const descriptor = buildCurrencyDescriptor(baseCurrency, baseRaw, quoteCurrency, quoteRaw, formatNumber, t`and`) + const descriptor = buildCurrencyDescriptor( + baseCurrency, + baseRaw, + quoteCurrency, + quoteRaw, + formatNumber, + t('common.and') + ) return { descriptor, currencies: [baseCurrency, quoteCurrency] } } @@ -166,8 +173,8 @@ async function parseMigrateCreateV3( getCurrency(lp.baseCurrencyId, chainId), getCurrency(lp.quoteCurrencyId, chainId), ]) - const baseSymbol = baseCurrency?.symbol ?? t`Unknown` - const quoteSymbol = quoteCurrency?.symbol ?? t`Unknown` + const baseSymbol = baseCurrency?.symbol ?? t('common.unknown') + const quoteSymbol = quoteCurrency?.symbol ?? t('common.unknown') const descriptor = t(`{{baseSymbol}} and {{quoteSymbol}}`, { baseSymbol, quoteSymbol }) return { descriptor, currencies: [baseCurrency, quoteCurrency] } @@ -185,10 +192,10 @@ async function parseSend( input: parseFloat(CurrencyAmount.fromRawAmount(currency, amount).toSignificant()), type: NumberType.TokenNonTx, }) - : t`Unknown` + : t('common.unknown') return { - descriptor: `${formattedAmount} ${currency?.symbol} ${t`to`} `, + descriptor: `${formattedAmount} ${currency?.symbol} ${t('common.to')} `, otherAccount: isAddress(recipient) || undefined, currencies: [currency], } @@ -199,7 +206,9 @@ export async function transactionToActivity( chainId: SupportedInterfaceChainId, formatNumber: FormatNumberFunctionType ): Promise { - if (!details) return undefined + if (!details) { + return undefined + } try { const defaultFields = { hash: details.hash, @@ -283,13 +292,17 @@ export async function signatureToActivity( signature: SignatureDetails | undefined, formatNumber: FormatNumberFunctionType ): Promise { - if (!signature) return undefined + if (!signature) { + return undefined + } switch (signature.type) { case SignatureType.SIGN_UNISWAPX_ORDER: case SignatureType.SIGN_UNISWAPX_V2_ORDER: case SignatureType.SIGN_LIMIT: { // Only returns Activity items for orders that don't have an on-chain counterpart - if (isOnChainOrder(signature.status)) return undefined + if (isOnChainOrder(signature.status)) { + return undefined + } const { title, statusMessage, status } = signature.type === SignatureType.SIGN_LIMIT @@ -330,7 +343,9 @@ export function useLocalActivities(account: string): ActivityMap { .map((signature) => signatureToActivity(signature, formatNumber)) return (await Promise.all([...transactions, ...signatures])).reduce((acc, activity) => { - if (activity) acc[activity.hash] = activity + if (activity) { + acc[activity.hash] = activity + } return acc }, {} as ActivityMap) }, diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/parseRemote.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/parseRemote.tsx index 1cd5b119fce..4d09d566b37 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/parseRemote.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/parseRemote.tsx @@ -48,34 +48,34 @@ const ENS_IMG = const COMMON_CONTRACTS: { [key: string]: Partial | undefined } = { [UNI_ADDRESSES[ChainId.MAINNET].toLowerCase()]: { - title: t`UNI Governance`, - descriptor: t`Contract Interaction`, + title: t('common.uniGovernance'), + descriptor: t('common.contractInteraction'), logos: [UNI_IMG], }, // TODO(cartcrom): Add permit2-specific logo '0x000000000022d473030f116ddee9f6b43ac78ba3': { - title: t`Permit2`, - descriptor: t`Uniswap Protocol`, + title: t('common.permit2'), + descriptor: t('common.uniswapProtocol'), logos: [UNI_IMG], }, '0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41': { - title: t`Ethereum Name Service`, - descriptor: t`Public Resolver`, + title: t('common.ethereumNameService'), + descriptor: t('common.publicResolver'), logos: [ENS_IMG], }, '0x58774bb8acd458a640af0b88238369a167546ef2': { - title: t`Ethereum Name Service`, - descriptor: t`DNS Registrar`, + title: t('common.ethereumNameService'), + descriptor: t('common.dnsRegistrar'), logos: [ENS_IMG], }, '0x084b1c3c81545d370f3634392de611caabff8148': { - title: t`Ethereum Name Service`, - descriptor: t`Reverse Registrar`, + title: t('common.ethereumNameService'), + descriptor: t('common.reverseRegistrar'), logos: [ENS_IMG], }, '0x283af0b28c62c092c9727f1ee09c02ca627eb7f5': { - title: t`Ethereum Name Service`, - descriptor: t`ETH Registrar Controller`, + title: t('common.ethereumNameService'), + descriptor: t('common.ethRegistrarController'), logos: [ENS_IMG], }, } @@ -86,13 +86,17 @@ function isSpam( details: TransactionDetailsPartsFragment, account: string ): boolean { - if (!SPAMMABLE_ACTIVITY_TYPES.includes(details.type) || details.from === account) return false + if (!SPAMMABLE_ACTIVITY_TYPES.includes(details.type) || details.from === account) { + return false + } return NftTransfer.some((nft) => nft.asset.isSpam) || TokenTransfer.some((t) => t.asset.project?.isSpam) } function callsPositionManagerContract(assetActivity: TransactionActivity) { const supportedChain = supportedChainIdFromGQLChain(assetActivity.chain) - if (!supportedChain) return false + if (!supportedChain) { + return false + } return isSameAddress(assetActivity.details.to, NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[supportedChain]) } @@ -120,15 +124,15 @@ function getSwapTitle(sent: TokenTransferPartsFragment, received: TokenTransferP if ( sent.tokenStandard === NATIVE_CHAIN_ID && isSameAddress(nativeOnChain(supportedSentChain).wrapped.address, received.asset.address) - ) - return t`Wrapped` - else if ( + ) { + return t('common.wrapped') + } else if ( received.tokenStandard === NATIVE_CHAIN_ID && isSameAddress(nativeOnChain(supportedReceivedChain).wrapped.address, received.asset.address) ) { - return t`Unwrapped` + return t('common.unwrapped') } else { - return t`Swapped` + return t('common.swapped') } } @@ -152,7 +156,9 @@ function getSwapDescriptor({ * @returns parsed & formatted USD value as a string if currency is of type USD */ function getTransactedValue(transactedValue: TokenTransferPartsFragment['transactedValue']): number | undefined { - if (!transactedValue) return undefined + if (!transactedValue) { + return undefined + } const price = transactedValue?.currency === GQLCurrency.Usd ? transactedValue.value ?? undefined : undefined return price } @@ -180,10 +186,14 @@ export function parseSwapAmounts( (t) => t.direction === 'IN' && t.asset.id === sent?.asset.id && t.asset.standard === NATIVE_CHAIN_ID ) const received = changes.TokenTransfer.find((t) => t.direction === 'IN' && t !== refund) - if (!sent || !received) return undefined + if (!sent || !received) { + return undefined + } const inputCurrencyId = sent.asset.standard === NATIVE_CHAIN_ID ? 'ETH' : sent.asset.address const outputCurrencyId = received.asset.standard === NATIVE_CHAIN_ID ? 'ETH' : received.asset.address - if (!inputCurrencyId || !outputCurrencyId) return undefined + if (!inputCurrencyId || !outputCurrencyId) { + return undefined + } const sentQuantity = parseUnits(sent.quantity, sent.asset.decimals) const refundQuantity = refund ? parseUnits(refund.quantity, refund.asset.decimals) : BigNumber.from(0) @@ -213,7 +223,7 @@ function parseSwap(changes: TransactionChanges, formatNumberOrString: FormatNumb if (changes.NftTransfer.length > 0 && changes.TokenTransfer.length === 1) { const collectionCounts = getCollectionCounts(changes.NftTransfer) - const title = changes.NftTransfer[0].direction === 'IN' ? t`Bought` : t`Sold` + const title = changes.NftTransfer[0].direction === 'IN' ? t('common.bought') : t('common.sold') const descriptor = Object.entries(collectionCounts) .map(([collectionName, count]) => `${count} ${collectionName}`) .join() @@ -233,7 +243,7 @@ function parseSwap(changes: TransactionChanges, formatNumberOrString: FormatNumb } } } - return { title: t`Unknown Swap` } + return { title: t('common.unknownSwap') } } /** @@ -246,7 +256,7 @@ function parseLend(changes: TransactionChanges, formatNumberOrString: FormatNumb if (native && erc20 && gqlToCurrency(native)?.wrapped.address === gqlToCurrency(erc20)?.wrapped.address) { return parseSwap(changes, formatNumberOrString) } - return { title: t`Unknown Lend` } + return { title: t('common.unknownLend') } } function parseSwapOrder( @@ -272,12 +282,18 @@ export function offchainOrderDetailsFromGraphQLTransactionActivity( formatNumberOrString: FormatNumberOrStringFunctionType ): UniswapXOrderDetails | undefined { const chainId = supportedChainIdFromGQLChain(activity.chain) - if (!activity || !activity.details || !chainId) return undefined - if (changes.TokenTransfer.length < 2) return undefined + if (!activity || !activity.details || !chainId) { + return undefined + } + if (changes.TokenTransfer.length < 2) { + return undefined + } const swapAmounts = parseSwapAmounts(changes, formatNumberOrString) - if (!swapAmounts) return undefined + if (!swapAmounts) { + return undefined + } const { inputCurrencyId, outputCurrencyId, inputAmountRaw, outputAmountRaw } = swapAmounts @@ -305,12 +321,12 @@ export function offchainOrderDetailsFromGraphQLTransactionActivity( function parseApprove(changes: TransactionChanges) { if (changes.TokenApproval.length === 1) { - const title = parseInt(changes.TokenApproval[0].quantity) === 0 ? t`Revoked Approval` : t`Approved` + const title = parseInt(changes.TokenApproval[0].quantity) === 0 ? t('common.revokedApproval') : t('common.approved') const descriptor = `${changes.TokenApproval[0].asset.symbol}` const currencies = [gqlToCurrency(changes.TokenApproval[0].asset)] return { title, descriptor, currencies } } - return { title: t`Unknown Approval` } + return { title: t('common.unknownApproval') } } function parseLPTransfers(changes: TransactionChanges, formatNumberOrString: FormatNumberOrStringFunctionType) { @@ -337,7 +353,7 @@ function parseSendReceive( // TODO(cartcrom): remove edge cases after backend implements // Edge case: Receiving two token transfers in interaction w/ V3 manager === removing liquidity. These edge cases should potentially be moved to backend if (changes.TokenTransfer.length === 2 && callsPositionManagerContract(assetActivity)) { - return { title: t`Removed Liquidity`, ...parseLPTransfers(changes, formatNumberOrString) } + return { title: t('common.removedLiquidity'), ...parseLPTransfers(changes, formatNumberOrString) } } let transfer: NftTransferPartsFragment | TokenTransferPartsFragment | undefined @@ -361,8 +377,8 @@ function parseSendReceive( if (transfer.direction === 'IN') { return isMoonpayPurchase && transfer.__typename === 'TokenTransfer' ? { - title: t`Purchased`, - descriptor: `${amount} ${assetName} ${t`for`} ${formatNumberOrString({ + title: t('common.purchased'), + descriptor: `${amount} ${assetName} ${t('for')} ${formatNumberOrString({ input: getTransactedValue(transfer.transactedValue), type: NumberType.FiatTokenPrice, })}`, @@ -370,21 +386,21 @@ function parseSendReceive( currencies, } : { - title: t`Received`, - descriptor: `${amount} ${assetName} ${t`from`} `, + title: t('common.received'), + descriptor: `${amount} ${assetName} ${t('common.from')} `, otherAccount: isAddress(transfer.sender) || undefined, currencies, } } else { return { - title: t`Sent`, - descriptor: `${amount} ${assetName} ${t`to`} `, + title: t('common.sent'), + descriptor: `${amount} ${assetName} ${t('common.to')} `, otherAccount: isAddress(transfer.recipient) || undefined, currencies, } } } - return { title: t`Unknown Send` } + return { title: t('common.unknownSend') } } function parseMint( @@ -398,11 +414,11 @@ function parseMint( // Edge case: Minting a v3 positon represents adding liquidity if (changes.TokenTransfer.length === 2 && callsPositionManagerContract(assetActivity)) { - return { title: t`Added Liquidity`, ...parseLPTransfers(changes, formatNumberOrString) } + return { title: t('common.addedLiquidity'), ...parseLPTransfers(changes, formatNumberOrString) } } - return { title: t`Minted`, descriptor: `${collectionMap[collectionName]} ${collectionName}` } + return { title: t('common.minted'), descriptor: `${collectionMap[collectionName]} ${collectionName}` } } - return { title: t`Unknown Mint` } + return { title: t('common.unknownMint') } } function parseUnknown( @@ -410,7 +426,7 @@ function parseUnknown( _formatNumberOrString: FormatNumberOrStringFunctionType, assetActivity: TransactionActivity ) { - return { title: t`Contract Interaction`, ...COMMON_CONTRACTS[assetActivity.details.to.toLowerCase()] } + return { title: t('common.contractInteraction'), ...COMMON_CONTRACTS[assetActivity.details.to.toLowerCase()] } } type TransactionTypeParser = ( @@ -492,11 +508,17 @@ function parseRemoteActivity( const changes = assetActivity.details.assetChanges.reduce( (acc: TransactionChanges, assetChange) => { - if (assetChange?.__typename === 'NftApproval') acc.NftApproval.push(assetChange) - else if (assetChange?.__typename === 'NftApproveForAll') acc.NftApproveForAll.push(assetChange) - else if (assetChange?.__typename === 'NftTransfer') acc.NftTransfer.push(assetChange) - else if (assetChange?.__typename === 'TokenTransfer') acc.TokenTransfer.push(assetChange) - else if (assetChange?.__typename === 'TokenApproval') acc.TokenApproval.push(assetChange) + if (assetChange?.__typename === 'NftApproval') { + acc.NftApproval.push(assetChange) + } else if (assetChange?.__typename === 'NftApproveForAll') { + acc.NftApproveForAll.push(assetChange) + } else if (assetChange?.__typename === 'NftTransfer') { + acc.NftTransfer.push(assetChange) + } else if (assetChange?.__typename === 'TokenTransfer') { + acc.TokenTransfer.push(assetChange) + } else if (assetChange?.__typename === 'TokenApproval') { + acc.TokenApproval.push(assetChange) + } return acc }, @@ -544,7 +566,9 @@ export function parseRemoteActivities( ) { return assetActivities?.reduce((acc: { [hash: string]: Activity }, assetActivity) => { const activity = parseRemoteActivity(assetActivity, account, formatNumberOrString) - if (activity) acc[activity.hash] = activity + if (activity) { + acc[activity.hash] = activity + } return acc }, {}) } @@ -554,12 +578,23 @@ const getTimeSince = (timestamp: number) => { let interval // TODO(cartcrom): use locale to determine date shorthands to use for non-english - if ((interval = seconds / ms(`1y`)) > 1) return Math.floor(interval) + 'y' - if ((interval = seconds / ms(`30d`)) > 1) return Math.floor(interval) + 'mo' - if ((interval = seconds / ms(`1d`)) > 1) return Math.floor(interval) + 'd' - if ((interval = seconds / ms(`1h`)) > 1) return Math.floor(interval) + 'h' - if ((interval = seconds / ms(`1m`)) > 1) return Math.floor(interval) + 'm' - else return Math.floor(seconds / ms(`1s`)) + 's' + if ((interval = seconds / ms(`1y`)) > 1) { + return Math.floor(interval) + 'y' + } + if ((interval = seconds / ms(`30d`)) > 1) { + return Math.floor(interval) + 'mo' + } + if ((interval = seconds / ms(`1d`)) > 1) { + return Math.floor(interval) + 'd' + } + if ((interval = seconds / ms(`1h`)) > 1) { + return Math.floor(interval) + 'h' + } + if ((interval = seconds / ms(`1m`)) > 1) { + return Math.floor(interval) + 'm' + } else { + return Math.floor(seconds / ms(`1s`)) + 's' + } } /** diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/utils.ts b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/utils.ts index 2fe945d75be..b3008d22ac1 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/utils.ts +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Activity/utils.ts @@ -1,25 +1,25 @@ import { TransactionRequest } from '@ethersproject/abstract-provider' import { Web3Provider } from '@ethersproject/providers' +import { PERMIT2_ADDRESS } from '@uniswap/permit2-sdk' import { ChainId } from '@uniswap/sdk-core' import { CosignedV2DutchOrder, DutchOrder } from '@uniswap/uniswapx-sdk' import { getYear, isSameDay, isSameMonth, isSameWeek, isSameYear } from 'date-fns' -import { t } from 'i18n' -import PERMIT2_ABI from 'uniswap/src/abis/permit2.json' -import { Permit2 } from 'uniswap/src/abis/types' -import { TransactionStatus } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' -import { didUserReject } from 'utils/swapErrorToUserReadableMessage' - -import { PERMIT2_ADDRESS } from '@uniswap/permit2-sdk' -import { sendAnalyticsEvent } from 'analytics' import { BigNumber, ContractTransaction } from 'ethers/lib/ethers' import { useContract } from 'hooks/useContract' import { useEthersWeb3Provider } from 'hooks/useEthersProvider' +import { t } from 'i18n' import { useCallback } from 'react' import store from 'state' import { updateSignature } from 'state/signatures/reducer' import { SignatureType, UniswapXOrderDetails } from 'state/signatures/types' import { UniswapXOrderStatus } from 'types/uniswapx' +import PERMIT2_ABI from 'uniswap/src/abis/permit2.json' +import { Permit2 } from 'uniswap/src/abis/types' +import { TransactionStatus } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' +import { InterfaceEventNameLocal } from 'uniswap/src/features/telemetry/constants' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { useAsyncData } from 'utilities/src/react/hooks' +import { didUserReject } from 'utils/swapErrorToUserReadableMessage' import { Activity } from './types' interface ActivityGroup { @@ -30,7 +30,9 @@ interface ActivityGroup { const sortActivities = (a: Activity, b: Activity) => b.timestamp - a.timestamp export const createGroups = (activities: Array = [], hideSpam = false) => { - if (activities.length === 0) return [] + if (activities.length === 0) { + return [] + } const now = Date.now() const pending: Array = [] @@ -78,11 +80,11 @@ export const createGroups = (activities: Array = [], hideSpam = false) .map((year) => ({ title: year, transactions: yearMap[year] })) const transactionGroups: Array = [ - { title: t`Pending`, transactions: pending.sort(sortActivities) }, - { title: t`Today`, transactions: today.sort(sortActivities) }, - { title: t`This week`, transactions: currentWeek.sort(sortActivities) }, - { title: t`This month`, transactions: last30Days.sort(sortActivities) }, - { title: t`This year`, transactions: currentYear.sort(sortActivities) }, + { title: t('common.pending'), transactions: pending.sort(sortActivities) }, + { title: t('common.today'), transactions: today.sort(sortActivities) }, + { title: t('common.thisWeek'), transactions: currentWeek.sort(sortActivities) }, + { title: t('common.thisMonth'), transactions: last30Days.sort(sortActivities) }, + { title: t('common.thisYear'), transactions: currentYear.sort(sortActivities) }, ...sortedYears, ] @@ -147,9 +149,11 @@ export function useCancelMultipleOrdersCallback( const permit2 = useContract(PERMIT2_ADDRESS, PERMIT2_ABI, true) return useCallback(async () => { - if (!orders || orders.length === 0) return undefined + if (!orders || orders.length === 0) { + return undefined + } - sendAnalyticsEvent('UniswapX Order Cancel Initiated', { + sendAnalyticsEvent(InterfaceEventNameLocal.UniswapXOrderCancelInitiated, { orders: orders.map((order) => order.orderHash), }) @@ -162,7 +166,9 @@ export function useCancelMultipleOrdersCallback( chainId: orders?.[0].chainId, }).then((result) => { orders.forEach((order) => { - if (order.status === UniswapXOrderStatus.FILLED) return + if (order.status === UniswapXOrderStatus.FILLED) { + return + } store.dispatch(updateSignature({ ...order, status: UniswapXOrderStatus.PENDING_CANCELLATION })) }) return result @@ -182,7 +188,9 @@ async function cancelMultipleUniswapXOrders({ provider?: Web3Provider }) { const cancelParams = getCancelMultipleUniswapXOrdersParams(orders, chainId) - if (!permit2 || !provider) return + if (!permit2 || !provider) { + return + } try { const transactions: ContractTransaction[] = [] for (const params of cancelParams) { @@ -191,7 +199,9 @@ async function cancelMultipleUniswapXOrders({ } return transactions } catch (error) { - if (!didUserReject(error)) console.error(error) + if (!didUserReject(error)) { + console.error(error) + } return undefined } } @@ -202,7 +212,9 @@ async function getCancelMultipleUniswapXOrdersTransaction( permit2: Permit2 ): Promise { const cancelParams = getCancelMultipleUniswapXOrdersParams(orders, chainId) - if (!permit2 || cancelParams.length === 0) return + if (!permit2 || cancelParams.length === 0) { + return + } try { const tx = await permit2.populateTransaction.invalidateUnorderedNonces(cancelParams[0].word, cancelParams[0].mask) return { @@ -230,8 +242,9 @@ export function useCreateCancelTransactionRequest( !params.orders || params.orders.filter(({ encodedOrder }) => Boolean(encodedOrder)).length === 0 || !permit2 - ) + ) { return + } return getCancelMultipleUniswapXOrdersTransaction(params.orders, params.chainId, permit2) }, [params, permit2]) diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/ExpandoRow.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/ExpandoRow.tsx index a76fceaba4e..4286a0317a2 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/ExpandoRow.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/ExpandoRow.tsx @@ -32,8 +32,10 @@ const Wrapper = styled(Column)<{ numItems: number; isExpanded: boolean }>` // TODO(WEB-1982): Replace this component to use `components/Expand` under the hood type ExpandoRowProps = PropsWithChildren<{ title?: string; numItems: number; isExpanded: boolean; toggle: () => void }> -export function ExpandoRow({ title = t`Hidden`, numItems, isExpanded, toggle, children }: ExpandoRowProps) { - if (numItems === 0) return null +export function ExpandoRow({ title = t('common.hidden'), numItems, isExpanded, toggle, children }: ExpandoRowProps) { + if (numItems === 0) { + return null + } return ( <> @@ -42,7 +44,7 @@ export function ExpandoRow({ title = t`Hidden`, numItems, isExpanded, toggle, ch - {isExpanded ? t`Hide` : t`Show`} + {isExpanded ? t('common.hide.button') : t('common.show.button')} diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/LimitDetailActivityRow.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/LimitDetailActivityRow.tsx index 87ff11efd5c..6d837625863 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/LimitDetailActivityRow.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/LimitDetailActivityRow.tsx @@ -63,7 +63,9 @@ export function LimitDetailActivityRow({ order, onToggleSelect, selected }: Limi const amountsDefined = !!amounts?.inputAmount?.currency && !!amounts?.outputAmount?.currency const displayPrice = useMemo(() => { - if (!amountsDefined) return undefined + if (!amountsDefined) { + return undefined + } const tradePrice = new Price({ baseAmount: amounts?.inputAmount, quoteAmount: amounts?.outputAmount }) return tradePrice.quote( CurrencyAmount.fromRawAmount( @@ -73,7 +75,9 @@ export function LimitDetailActivityRow({ order, onToggleSelect, selected }: Limi ) }, [amounts?.inputAmount, amounts?.outputAmount, amountsDefined]) - if (!offchainOrderDetails || !amountsDefined) return null + if (!offchainOrderDetails || !amountsDefined) { + return null + } const inputLogo = logos?.[0] ?? inputCurrencyInfo?.logoUrl const outputLogo = logos?.[1] ?? outputCurrencyInfo?.logoUrl @@ -87,13 +91,14 @@ export function LimitDetailActivityRow({ order, onToggleSelect, selected }: Limi title={ cancelling ? ( - Pending cancellation + ) : offchainOrderDetails?.expiry ? ( - - Expires {{ timestamp: formatTimestamp(offchainOrderDetails.expiry * 1000, true, FormatType.Short) }} - + ) : undefined } @@ -112,11 +117,14 @@ export function LimitDetailActivityRow({ order, onToggleSelect, selected }: Limi {displayPrice && ( - - when {{ price: formatReviewSwapCurrencyAmount(displayPrice) }}{' '} - {{ outSymbol: amounts.outputAmount.currency.symbol }}/ - {{ inSymbol: amounts.inputAmount.currency.symbol }} - + )} diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/LimitsMenu.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/LimitsMenu.tsx index 3581d43cbbc..6e0466a0799 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/LimitsMenu.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/LimitsMenu.tsx @@ -54,7 +54,7 @@ export function LimitsMenu({ onClose, account }: { account: string; onClose: () } return ( - Open limits} onClose={onClose}> + } onClose={onClose}> {openLimitOrders.map((order) => ( @@ -74,8 +74,8 @@ export function LimitsMenu({ onClose, account }: { account: string; onClose: () > )} diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/OpenLimitOrdersButton.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/OpenLimitOrdersButton.tsx index afa52b2b647..0602ba2d482 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/OpenLimitOrdersButton.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Limits/OpenLimitOrdersButton.tsx @@ -2,7 +2,7 @@ import { useOpenLimitOrders } from 'components/AccountDrawer/MiniPortfolio/Activ import Column from 'components/Column' import { TimeForwardIcon } from 'components/Icons/TimeForward' import Row from 'components/Row' -import { Plural, t, Trans } from 'i18n' +import { Plural, Trans, t } from 'i18n' import { ChevronRight } from 'react-feather' import styled, { useTheme } from 'styled-components' import { ClickableStyle, ThemedText } from 'theme/components' @@ -17,8 +17,12 @@ const Container = styled.button` ` function getExtraWarning(openLimitOrders: any[]) { - if (openLimitOrders.length >= 100) return Cancel limits to proceed - if (openLimitOrders.length >= 90) return Approaching 100 limit maximum + if (openLimitOrders.length >= 100) { + return + } + if (openLimitOrders.length >= 90) { + return + } return undefined } @@ -36,7 +40,9 @@ export function OpenLimitOrdersButton({ const { openLimitOrders } = useOpenLimitOrders(account) const theme = useTheme() const extraWarning = getExtraWarning(openLimitOrders) - if (!openLimitOrders || openLimitOrders.length < 1) return null + if (!openLimitOrders || openLimitOrders.length < 1) { + return null + } return ( @@ -46,8 +52,8 @@ export function OpenLimitOrdersButton({ {extraWarning && {extraWarning}} diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/NFTs/NFTItem.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/NFTs/NFTItem.tsx index b0625adc348..c96516e832a 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/NFTs/NFTItem.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/NFTs/NFTItem.tsx @@ -1,5 +1,4 @@ import { InterfaceElementName, SharedEventName } from '@uniswap/analytics-events' -import { sendAnalyticsEvent, useTrace } from 'analytics' import Column from 'components/Column' import Row from 'components/Row' import { Box } from 'nft/components/Box' @@ -10,8 +9,9 @@ import { WalletAsset } from 'nft/types' import { useNavigate } from 'react-router-dom' import styled from 'styled-components' import { ThemedText } from 'theme/components' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { NumberType, useFormatter } from 'utils/formatNumbers' - import { useToggleAccountDrawer } from '../hooks' const FloorPrice = styled(Row)` diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/NFTs/index.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/NFTs/index.tsx index e156943f379..422a23dcec6 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/NFTs/index.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/NFTs/index.tsx @@ -24,12 +24,13 @@ export default function NFTs({ account }: { account: string }) { const [currentTokenPlayingMedia, setCurrentTokenPlayingMedia] = useState() - if (loading && !walletAssets) + if (loading && !walletAssets) { return ( ) + } if (!walletAssets || walletAssets?.length === 0) { return diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/getTokensAsync.ts b/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/getTokensAsync.ts index 0d372ca3934..f07c0381b06 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/getTokensAsync.ts +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/getTokensAsync.ts @@ -65,7 +65,9 @@ function parseTokens(addresses: string[], chainId: ChainId, returnData: CallResu return tokenDataSlices.reduce((acc: TokenMap, slice, index) => { const parsedToken = tryParseToken(addresses[index], chainId, slice) - if (parsedToken) acc[parsedToken.address] = parsedToken + if (parsedToken) { + acc[parsedToken.address] = parsedToken + } return acc }, {}) } @@ -92,7 +94,9 @@ export async function getTokensAsync( chainId: ChainId, multicall: UniswapInterfaceMulticall ): Promise { - if (addresses.length === 0) return {} + if (addresses.length === 0) { + return {} + } const formattedAddresses: string[] = [] const calls: Call[] = [] const previouslyCalledTokens: Promise[] = [] @@ -104,7 +108,9 @@ export async function getTokensAsync( previouslyCalledTokens.push(previousCall) } else { const formattedAddress = isAddress(tokenAddress) - if (!formattedAddress) return + if (!formattedAddress) { + return + } formattedAddresses.push(formattedAddress) calls.push(...createCallsForToken(formattedAddress)) } diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/hooks.ts b/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/hooks.ts index 59b77feaf6c..6ef4e845e9d 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/hooks.ts +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/hooks.ts @@ -67,7 +67,9 @@ export function useInterfaceMulticallContracts(chainIds: ChainId[]): ContractMap type PriceMap = { [key: CurrencyKey]: number | undefined } export function usePoolPriceMap(positions: PositionInfo[] | undefined) { const contracts = useMemo(() => { - if (!positions || !positions.length) return [] + if (!positions || !positions.length) { + return [] + } // Avoids fetching duplicate tokens by placing in map const contractMap = positions.reduce((acc: { [key: string]: ContractInput }, { pool: { token0, token1 } }) => { acc[currencyKey(token0)] = toContractInput(token0) @@ -82,7 +84,9 @@ export function usePoolPriceMap(positions: PositionInfo[] | undefined) { const priceMap = useMemo( () => data?.tokens?.reduce((acc: PriceMap, current) => { - if (current) acc[currencyKeyFromGraphQL(current)] = current.project?.markets?.[0]?.price?.value + if (current) { + acc[currencyKeyFromGraphQL(current)] = current.project?.markets?.[0]?.price?.value + } return acc }, {}) ?? {}, [data?.tokens] diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/index.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/index.tsx index 21f83e3f4c6..6e0f3098414 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/index.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/index.tsx @@ -1,7 +1,6 @@ -import { BrowserEvent, InterfaceElementName, SharedEventName } from '@uniswap/analytics-events' +import { InterfaceElementName } from '@uniswap/analytics-events' import { Position } from '@uniswap/v3-sdk' import { useWeb3React } from '@web3-react/core' -import { TraceEvent } from 'analytics' import Row from 'components/Row' import { MouseoverTooltip } from 'components/Tooltip' import { BIPS_BASE } from 'constants/misc' @@ -13,8 +12,8 @@ import { useCallback, useMemo, useReducer } from 'react' import { useNavigate } from 'react-router-dom' import styled from 'styled-components' import { ThemedText } from 'theme/components' +import Trace from 'uniswap/src/features/telemetry/Trace' import { NumberType, useFormatter } from 'utils/formatNumbers' - import { ExpandoRow } from '../ExpandoRow' import { PortfolioLogo } from '../PortfolioLogo' import PortfolioRow, { PortfolioSkeleton, PortfolioTabWrapper } from '../PortfolioRow' @@ -111,7 +110,9 @@ const ActiveDot = styled.span<{ closed: boolean; outOfRange: boolean }>` ` function calculateLiquidityValue(price0: number | undefined, price1: number | undefined, position: Position) { - if (!price0 || !price1) return undefined + if (!price0 || !price1) { + return undefined + } const value0 = parseFloat(position.amount0.toExact()) * price0 const value1 = parseFloat(position.amount1.toExact()) * price1 @@ -131,7 +132,9 @@ function PositionListItem({ positionInfo }: { positionInfo: PositionInfo }) { const { chainId: walletChainId } = useWeb3React() const switchChain = useSwitchChain() const onClick = useCallback(async () => { - if (walletChainId !== chainId) await switchChain(chainId) + if (walletChainId !== chainId) { + await switchChain(chainId) + } toggleWalletDrawer() navigate('/pool/' + details.tokenId) }, [walletChainId, chainId, switchChain, toggleWalletDrawer, navigate, details.tokenId]) @@ -147,12 +150,7 @@ function PositionListItem({ positionInfo }: { positionInfo: PositionInfo }) { ) return ( - + } @@ -190,13 +188,13 @@ function PositionListItem({ positionInfo }: { positionInfo: PositionInfo }) { - {closed ? t`Closed` : inRange ? t`In range` : t`Out of range`} + {closed ? t('common.closed') : inRange ? t('common.withinRange') : t('common.outOfRange')} } /> - + ) } diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/useMultiChainPositions.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/useMultiChainPositions.tsx index a54c97ccf32..4070fa07e03 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/useMultiChainPositions.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Pools/useMultiChainPositions.tsx @@ -161,7 +161,9 @@ export default function useMultiChainPositions(account: string, chains = DEFAULT const pm = pms[chainId] const multicall = multicalls[chainId] const balance = await pm?.balanceOf(account) - if (!pm || !multicall || balance.lt(1)) return [] + if (!pm || !multicall || balance.lt(1)) { + return [] + } const positionIds = await fetchPositionIds(pm, balance) // Fetches fees in the background and stores them separetely from the results of this function @@ -186,8 +188,9 @@ export default function useMultiChainPositions(account: string, chains = DEFAULT // Fetches positions when existing positions are stale and the document has focus useEffect(() => { - if (positionsFetching.current || cachedPositions?.stale === false) return - else if (document.hasFocus()) { + if (positionsFetching.current || cachedPositions?.stale === false) { + return + } else if (document.hasFocus()) { fetchAllPositions() } else { // Avoids refetching positions until the user returns to Interface to avoid polling unnused rpc data diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/PortfolioLogo.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/PortfolioLogo.tsx index d1097cebf8a..863e4176cfc 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/PortfolioLogo.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/PortfolioLogo.tsx @@ -35,7 +35,9 @@ interface PortfolioLogoProps { } function SquareL2Logo({ chainId, size }: { chainId: ChainId; size: number }) { - if (chainId === ChainId.MAINNET) return null + if (chainId === ChainId.MAINNET) { + return null + } return ( diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/Tokens/index.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/Tokens/index.tsx index b295e4f9c6e..7d948040ab7 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/Tokens/index.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/Tokens/index.tsx @@ -1,8 +1,8 @@ -import { BrowserEvent, InterfaceElementName, SharedEventName } from '@uniswap/analytics-events' -import { TraceEvent } from 'analytics' +import { InterfaceElementName } from '@uniswap/analytics-events' import { hideSpamAtom } from 'components/AccountDrawer/SpamToggle' import Row from 'components/Row' import { DeltaArrow } from 'components/Tokens/TokenDetails/Delta' +import { useTokenBalancesQuery } from 'graphql/data/apollo/TokenBalancesProvider' import { PortfolioToken } from 'graphql/data/portfolios' import { getTokenDetailsURL, gqlToCurrency, logSentryErrorForUnsupportedChain } from 'graphql/data/util' import { useAtomValue } from 'jotai/utils' @@ -12,10 +12,9 @@ import { useNavigate } from 'react-router-dom' import styled from 'styled-components' import { EllipsisStyle, ThemedText } from 'theme/components' import { PortfolioTokenBalancePartsFragment } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' +import Trace from 'uniswap/src/features/telemetry/Trace' import { NumberType, useFormatter } from 'utils/formatNumbers' import { splitHiddenTokens } from 'utils/splitHiddenTokens' - -import { useTokenBalancesQuery } from 'graphql/data/apollo/TokenBalancesProvider' import { hideSmallBalancesAtom } from '../../SmallBalanceToggle' import { ExpandoRow } from '../ExpandoRow' import { PortfolioLogo } from '../PortfolioLogo' @@ -98,15 +97,18 @@ function TokenRow({ return null } return ( - } - title={{token?.name}} + title={{token?.project?.name ?? token?.name}} descriptor={ {formatNumber({ @@ -134,6 +136,6 @@ function TokenRow({ ) } /> - + ) } diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/constants.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/constants.tsx index bae16944f57..96555d8c74e 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/constants.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/constants.tsx @@ -8,189 +8,191 @@ export const DEFAULT_NFT_QUERY_AMOUNT = 26 const TransactionTitleTable: { [key in TransactionType]: { [state in TransactionStatus]: string } } = { [TransactionType.SWAP]: { - [TransactionStatus.Pending]: t`Swapping`, - [TransactionStatus.Confirmed]: t`Swapped`, - [TransactionStatus.Failed]: t`Swap failed`, + [TransactionStatus.Pending]: t('common.swapping'), + [TransactionStatus.Confirmed]: t('common.swapped'), + [TransactionStatus.Failed]: t('common.swap.failed'), }, [TransactionType.WRAP]: { - [TransactionStatus.Pending]: t`Wrapping`, - [TransactionStatus.Confirmed]: t`Wrapped`, - [TransactionStatus.Failed]: t`Wrap failed`, + [TransactionStatus.Pending]: t('common.wrapping'), + [TransactionStatus.Confirmed]: t('common.wrapped'), + [TransactionStatus.Failed]: t('common.wrap.failed'), }, [TransactionType.ADD_LIQUIDITY_V3_POOL]: { - [TransactionStatus.Pending]: t`Adding liquidity`, - [TransactionStatus.Confirmed]: t`Added liquidity`, - [TransactionStatus.Failed]: t`Add liquidity failed`, + [TransactionStatus.Pending]: t('common.adding.liquidity'), + [TransactionStatus.Confirmed]: t('common.added.liquidity'), + [TransactionStatus.Failed]: t('common.add.liquidity.failed'), }, [TransactionType.REMOVE_LIQUIDITY_V3]: { - [TransactionStatus.Pending]: t`Removing liquidity`, - [TransactionStatus.Confirmed]: t`Removed liquidity`, - [TransactionStatus.Failed]: t`Remove liquidity failed`, + [TransactionStatus.Pending]: t('common.removing.liquidity'), + [TransactionStatus.Confirmed]: t('common.removed.liquidity'), + [TransactionStatus.Failed]: t('common.remove.liquidity.failed'), }, [TransactionType.CREATE_V3_POOL]: { - [TransactionStatus.Pending]: t`Creating pool`, - [TransactionStatus.Confirmed]: t`Created pool`, - [TransactionStatus.Failed]: t`Create pool failed`, + [TransactionStatus.Pending]: t('common.creating.pool'), + [TransactionStatus.Confirmed]: t('common.created.pool'), + [TransactionStatus.Failed]: t('common.create.pool.failed'), }, [TransactionType.COLLECT_FEES]: { - [TransactionStatus.Pending]: t`Collecting fees`, - [TransactionStatus.Confirmed]: t`Collected fees`, - [TransactionStatus.Failed]: t`Collect fees failed`, + [TransactionStatus.Pending]: t('common.collecting.fees'), + [TransactionStatus.Confirmed]: t('common.collected.fees'), + [TransactionStatus.Failed]: t('common.collect.fees.failed'), }, [TransactionType.APPROVAL]: { - [TransactionStatus.Pending]: t`Approving`, - [TransactionStatus.Confirmed]: t`Approved`, - [TransactionStatus.Failed]: t`Approval failed`, + [TransactionStatus.Pending]: t('common.approving'), + [TransactionStatus.Confirmed]: t('common.approved'), + [TransactionStatus.Failed]: t('common.approval.failed'), }, [TransactionType.CLAIM]: { - [TransactionStatus.Pending]: t`Claiming`, - [TransactionStatus.Confirmed]: t`Claimed`, - [TransactionStatus.Failed]: t`Claim failed`, + [TransactionStatus.Pending]: t('common.claiming'), + [TransactionStatus.Confirmed]: t('common.claimed'), + [TransactionStatus.Failed]: t('common.claim.failed'), }, [TransactionType.BUY]: { - [TransactionStatus.Pending]: t`Buying`, - [TransactionStatus.Confirmed]: t`Bought`, - [TransactionStatus.Failed]: t`Buy failed`, + [TransactionStatus.Pending]: t('Buying'), + [TransactionStatus.Confirmed]: t('common.bought'), + [TransactionStatus.Failed]: t('common.buy.failed'), }, [TransactionType.SEND]: { - [TransactionStatus.Pending]: t`Sending`, - [TransactionStatus.Confirmed]: t`Sent`, - [TransactionStatus.Failed]: t`Send failed`, + [TransactionStatus.Pending]: t('common.sending'), + [TransactionStatus.Confirmed]: t('common.sent'), + [TransactionStatus.Failed]: t('common.send.failed'), }, [TransactionType.RECEIVE]: { - [TransactionStatus.Pending]: t`Receiving`, - [TransactionStatus.Confirmed]: t`Received`, - [TransactionStatus.Failed]: t`Receive failed`, + [TransactionStatus.Pending]: t('common.receiving'), + [TransactionStatus.Confirmed]: t('common.received'), + [TransactionStatus.Failed]: t('common.receive.failed'), }, [TransactionType.MINT]: { - [TransactionStatus.Pending]: t`Minting`, - [TransactionStatus.Confirmed]: t`Minted`, - [TransactionStatus.Failed]: t`Mint failed`, + [TransactionStatus.Pending]: t('common.minting'), + [TransactionStatus.Confirmed]: t('common.minted'), + [TransactionStatus.Failed]: t('common.mint.failed'), }, [TransactionType.BURN]: { - [TransactionStatus.Pending]: t`Burning`, - [TransactionStatus.Confirmed]: t`Burned`, - [TransactionStatus.Failed]: t`Burn failed`, + [TransactionStatus.Pending]: t('common.burning'), + [TransactionStatus.Confirmed]: t('common.burned'), + [TransactionStatus.Failed]: t('common.burn.failed'), }, [TransactionType.VOTE]: { - [TransactionStatus.Pending]: t`Voting`, - [TransactionStatus.Confirmed]: t`Voted`, - [TransactionStatus.Failed]: t`Vote failed`, + [TransactionStatus.Pending]: t('common.voting'), + [TransactionStatus.Confirmed]: t('common.voted'), + [TransactionStatus.Failed]: t('common.vote.failed'), }, [TransactionType.QUEUE]: { - [TransactionStatus.Pending]: t`Queuing`, - [TransactionStatus.Confirmed]: t`Queued`, - [TransactionStatus.Failed]: t`Queue failed`, + [TransactionStatus.Pending]: t('common.queuing'), + [TransactionStatus.Confirmed]: t('common.queued'), + [TransactionStatus.Failed]: t('common.queue.failed'), }, [TransactionType.EXECUTE]: { - [TransactionStatus.Pending]: t`Executing`, - [TransactionStatus.Confirmed]: t`Executed`, - [TransactionStatus.Failed]: t`Execute failed`, + [TransactionStatus.Pending]: t('common.executing'), + [TransactionStatus.Confirmed]: t('common.executed'), + [TransactionStatus.Failed]: t('common.execute.failed'), }, [TransactionType.BORROW]: { - [TransactionStatus.Pending]: t`Borrowing`, - [TransactionStatus.Confirmed]: t`Borrowed`, - [TransactionStatus.Failed]: t`Borrow failed`, + [TransactionStatus.Pending]: t('common.borrowing'), + [TransactionStatus.Confirmed]: t('common.borrowed'), + [TransactionStatus.Failed]: t('common.borrow.failed'), }, [TransactionType.REPAY]: { - [TransactionStatus.Pending]: t`Repaying`, - [TransactionStatus.Confirmed]: t`Repaid`, - [TransactionStatus.Failed]: t`Repay failed`, + [TransactionStatus.Pending]: t('common.repaying'), + [TransactionStatus.Confirmed]: t('common.repaid'), + [TransactionStatus.Failed]: t('common.repay.failed'), }, [TransactionType.DEPLOY]: { - [TransactionStatus.Pending]: t`Deploying`, - [TransactionStatus.Confirmed]: t`Deployed`, - [TransactionStatus.Failed]: t`Deploy failed`, + [TransactionStatus.Pending]: t('common.deploying'), + [TransactionStatus.Confirmed]: t('common.deployed'), + [TransactionStatus.Failed]: t('common.deploy.failed'), }, [TransactionType.CANCEL]: { - [TransactionStatus.Pending]: t`Cancelling`, - [TransactionStatus.Confirmed]: t`Cancelled`, - [TransactionStatus.Failed]: t`Cancel failed`, + [TransactionStatus.Pending]: t('common.cancelling'), + [TransactionStatus.Confirmed]: t('common.cancelled'), + [TransactionStatus.Failed]: t('common.cancel.failed'), }, [TransactionType.DELEGATE]: { - [TransactionStatus.Pending]: t`Delegating`, - [TransactionStatus.Confirmed]: t`Delegated`, - [TransactionStatus.Failed]: t`Delegate failed`, + [TransactionStatus.Pending]: t('common.delegating'), + [TransactionStatus.Confirmed]: t('common.delegated'), + [TransactionStatus.Failed]: t('common.delegate.failed'), }, [TransactionType.DEPOSIT_LIQUIDITY_STAKING]: { - [TransactionStatus.Pending]: t`Depositing`, - [TransactionStatus.Confirmed]: t`Deposited`, - [TransactionStatus.Failed]: t`Deposit failed`, + [TransactionStatus.Pending]: t('common.depositing'), + [TransactionStatus.Confirmed]: t('common.deposited'), + [TransactionStatus.Failed]: t('common.deposit.failed'), }, [TransactionType.WITHDRAW_LIQUIDITY_STAKING]: { - [TransactionStatus.Pending]: t`Withdrawing`, - [TransactionStatus.Confirmed]: t`Withdrew`, - [TransactionStatus.Failed]: t`Withdraw failed`, + [TransactionStatus.Pending]: t('common.withdrawing'), + [TransactionStatus.Confirmed]: t('common.withdrew'), + [TransactionStatus.Failed]: t('common.withdraw.failed'), }, [TransactionType.ADD_LIQUIDITY_V2_POOL]: { - [TransactionStatus.Pending]: t`Adding V2 liquidity`, - [TransactionStatus.Confirmed]: t`Added V2 liquidity`, - [TransactionStatus.Failed]: t`Add V2 liquidity failed`, + [TransactionStatus.Pending]: t('common.adding.v2.liquidity'), + [TransactionStatus.Confirmed]: t('common.added.v2.liquidity'), + [TransactionStatus.Failed]: t('common.add.v2.liquidity.failed'), }, [TransactionType.MIGRATE_LIQUIDITY_V3]: { - [TransactionStatus.Pending]: t`Migrating liquidity`, - [TransactionStatus.Confirmed]: t`Migrated liquidity`, - [TransactionStatus.Failed]: t`Migrate liquidity failed`, + [TransactionStatus.Pending]: t('common.migrating.liquidity'), + [TransactionStatus.Confirmed]: t('common.migrated.liquidity'), + [TransactionStatus.Failed]: t('common.migrate.liquidity.failed'), }, [TransactionType.SUBMIT_PROPOSAL]: { - [TransactionStatus.Pending]: t`Submitting proposal`, - [TransactionStatus.Confirmed]: t`Submitted proposal`, - [TransactionStatus.Failed]: t`Submit proposal failed`, + [TransactionStatus.Pending]: t('common.submitting.proposal'), + [TransactionStatus.Confirmed]: t('common.submitted.proposal'), + [TransactionStatus.Failed]: t('common.submit.proposal.failed'), }, [TransactionType.LIMIT]: { - [TransactionStatus.Pending]: t`Limit opened`, - [TransactionStatus.Confirmed]: t`Limit executed`, - [TransactionStatus.Failed]: t`Limit failed`, + [TransactionStatus.Pending]: t('common.limit.opened'), + [TransactionStatus.Confirmed]: t('common.limit.executed'), + [TransactionStatus.Failed]: t('common.limit.failed'), }, } export const CancelledTransactionTitleTable: { [key in TransactionType]: string } = { - [TransactionType.SWAP]: t`Swap cancelled`, - [TransactionType.WRAP]: t`Wrap cancelled`, - [TransactionType.ADD_LIQUIDITY_V3_POOL]: t`Add liquidity cancelled`, - [TransactionType.REMOVE_LIQUIDITY_V3]: t`Remove liquidity cancelled`, - [TransactionType.CREATE_V3_POOL]: t`Create pool cancelled`, - [TransactionType.COLLECT_FEES]: t`Collect fees cancelled`, - [TransactionType.APPROVAL]: t`Approval cancelled`, - [TransactionType.CLAIM]: t`Claim cancelled`, - [TransactionType.BUY]: t`Buy cancelled`, - [TransactionType.SEND]: t`Send cancelled`, - [TransactionType.RECEIVE]: t`Receive cancelled`, - [TransactionType.MINT]: t`Mint cancelled`, - [TransactionType.BURN]: t`Burn cancelled`, - [TransactionType.VOTE]: t`Vote cancelled`, - [TransactionType.QUEUE]: t`Queue cancelled`, - [TransactionType.EXECUTE]: t`Execute cancelled`, - [TransactionType.BORROW]: t`Borrow cancelled`, - [TransactionType.REPAY]: t`Repay cancelled`, - [TransactionType.DEPLOY]: t`Deploy cancelled`, - [TransactionType.CANCEL]: t`Cancellation cancelled`, - [TransactionType.DELEGATE]: t`Delegate cancelled`, - [TransactionType.DEPOSIT_LIQUIDITY_STAKING]: t`Deposit cancelled`, - [TransactionType.WITHDRAW_LIQUIDITY_STAKING]: t`Withdrawal cancelled`, - [TransactionType.ADD_LIQUIDITY_V2_POOL]: t`Add V2 liquidity cancelled`, - [TransactionType.MIGRATE_LIQUIDITY_V3]: t`Migrate liquidity cancelled`, - [TransactionType.SUBMIT_PROPOSAL]: t`Submit proposal cancelled`, - [TransactionType.LIMIT]: t`Limit cancelled`, + [TransactionType.SWAP]: t('common.swap.cancelled'), + [TransactionType.WRAP]: t('common.wrap.cancelled'), + [TransactionType.ADD_LIQUIDITY_V3_POOL]: t('common.add.liquidity.cancelled'), + [TransactionType.REMOVE_LIQUIDITY_V3]: t('common.remove.liquidity.cancelled'), + [TransactionType.CREATE_V3_POOL]: t('common.create.pool.cancelled'), + [TransactionType.COLLECT_FEES]: t('common.collect.fees.cancelled'), + [TransactionType.APPROVAL]: t('common.approval.cancelled'), + [TransactionType.CLAIM]: t('common.claim.cancelled'), + [TransactionType.BUY]: t('common.buy.cancelled'), + [TransactionType.SEND]: t('common.send.cancelled'), + [TransactionType.RECEIVE]: t('common.receive.cancelled'), + [TransactionType.MINT]: t('common.mint.cancelled'), + [TransactionType.BURN]: t('common.burn.cancelled'), + [TransactionType.VOTE]: t('common.vote.cancelled'), + [TransactionType.QUEUE]: t('common.queue.cancelled'), + [TransactionType.EXECUTE]: t('common.execute.cancelled'), + [TransactionType.BORROW]: t('common.borrow.cancelled'), + [TransactionType.REPAY]: t('common.repay.cancelled'), + [TransactionType.DEPLOY]: t('common.deploy.cancelled'), + [TransactionType.CANCEL]: t('common.cancellation.cancelled'), + [TransactionType.DELEGATE]: t('common.delegate.cancelled'), + [TransactionType.DEPOSIT_LIQUIDITY_STAKING]: t('common.deposit.cancelled'), + [TransactionType.WITHDRAW_LIQUIDITY_STAKING]: t('common.withdrawal.cancelled'), + [TransactionType.ADD_LIQUIDITY_V2_POOL]: t('common.add.v2.liquidity.cancelled'), + [TransactionType.MIGRATE_LIQUIDITY_V3]: t('common.migrate.liquidity.cancelled'), + [TransactionType.SUBMIT_PROPOSAL]: t('common.submit.proposal.cancelled'), + [TransactionType.LIMIT]: t('common.limit.cancelled'), } const AlternateTransactionTitleTable: { [key in TransactionType]?: { [state in TransactionStatus]: string } } = { [TransactionType.WRAP]: { - [TransactionStatus.Pending]: t`Unwrapping`, - [TransactionStatus.Confirmed]: t`Unwrapped`, - [TransactionStatus.Failed]: t`Unwrap failed`, + [TransactionStatus.Pending]: t('common.unwrapping'), + [TransactionStatus.Confirmed]: t('common.unwrapped'), + [TransactionStatus.Failed]: t('common.unwrap.failed'), }, [TransactionType.APPROVAL]: { - [TransactionStatus.Pending]: t`Revoking approval`, - [TransactionStatus.Confirmed]: t`Revoked approval`, - [TransactionStatus.Failed]: t`Revoke approval failed`, + [TransactionStatus.Pending]: t('common.revoking.approval'), + [TransactionStatus.Confirmed]: t('common.revoked.approval'), + [TransactionStatus.Failed]: t('common.revoke.approval.failed'), }, } export function getActivityTitle(type: TransactionType, status: TransactionStatus, alternate?: boolean) { if (alternate) { const alternateTitle = AlternateTransactionTitleTable[type] - if (alternateTitle !== undefined) return alternateTitle[status] + if (alternateTitle !== undefined) { + return alternateTitle[status] + } } return TransactionTitleTable[type][status] } @@ -208,8 +210,8 @@ export const OrderTextTable: { status: TransactionStatus.Confirmed, }, [UniswapXOrderStatus.EXPIRED]: { - title: t`Swap expired`, - statusMessage: t`Your swap could not be fulfilled at this time. Please try again.`, + title: t('common.swap.expired'), + statusMessage: t('common.your.swap.could.not.be.fulfilled'), status: TransactionStatus.Failed, }, [UniswapXOrderStatus.ERROR]: { @@ -217,16 +219,16 @@ export const OrderTextTable: { status: TransactionStatus.Failed, }, [UniswapXOrderStatus.INSUFFICIENT_FUNDS]: { - title: t`Insufficient funds`, - statusMessage: t`Your account had insufficient funds to complete this swap.`, + title: t('common.insufficient.funds'), + statusMessage: t('common.your.account.had.insufficient.funds'), status: TransactionStatus.Failed, }, [UniswapXOrderStatus.PENDING_CANCELLATION]: { - title: t`Pending cancellation`, + title: t('common.pending.cancellation'), status: TransactionStatus.Pending, }, [UniswapXOrderStatus.CANCELLED]: { - title: t`Swap cancelled`, + title: t('common.swap.cancelled'), status: TransactionStatus.Failed, }, } @@ -244,8 +246,8 @@ export const LimitOrderTextTable: { status: TransactionStatus.Confirmed, }, [UniswapXOrderStatus.EXPIRED]: { - title: t`Limit expired`, - statusMessage: t`Your limit could not be fulfilled at this time. Please try again.`, + title: t('common.limit.expired'), + statusMessage: t('common.your.limit.could.not.be.fulfilled'), status: TransactionStatus.Failed, }, [UniswapXOrderStatus.ERROR]: { @@ -254,15 +256,15 @@ export const LimitOrderTextTable: { }, [UniswapXOrderStatus.INSUFFICIENT_FUNDS]: { title: LimitTitleTable.PENDING, - statusMessage: t`Your account has insufficient funds to complete this swap.`, + statusMessage: t('common.your.account.has.insufficient.funds'), status: TransactionStatus.Pending, }, [UniswapXOrderStatus.PENDING_CANCELLATION]: { - title: t`Pending cancellation`, + title: t('common.pending.cancellation'), status: TransactionStatus.Pending, }, [UniswapXOrderStatus.CANCELLED]: { - title: t`Limit cancelled`, + title: t('common.limit.cancelled'), status: TransactionStatus.Failed, }, } diff --git a/apps/web/src/components/AccountDrawer/MiniPortfolio/index.tsx b/apps/web/src/components/AccountDrawer/MiniPortfolio/index.tsx index d3715b840c6..6f63958802c 100644 --- a/apps/web/src/components/AccountDrawer/MiniPortfolio/index.tsx +++ b/apps/web/src/components/AccountDrawer/MiniPortfolio/index.tsx @@ -1,17 +1,16 @@ -import { BrowserEvent, InterfaceElementName, InterfaceSectionName, SharedEventName } from '@uniswap/analytics-events' -import { Trace, TraceEvent } from 'analytics' +import { InterfaceElementName, InterfaceSectionName, SharedEventName } from '@uniswap/analytics-events' import Column from 'components/Column' import { LoaderV2 } from 'components/Icons/LoadingSpinner' import { AutoRow } from 'components/Row' import { useDisableNFTRoutes } from 'hooks/useDisableNFTRoutes' import { useIsNftPage } from 'hooks/useIsNftPage' import { Trans } from 'i18n' +import { atom, useAtom } from 'jotai' import { useEffect, useState } from 'react' import styled, { useTheme } from 'styled-components' import { BREAKPOINTS } from 'theme' import { ThemedText } from 'theme/components' - -import { atom, useAtom } from 'jotai' +import Trace from 'uniswap/src/features/telemetry/Trace' import { ActivityTab } from './Activity' import { usePendingActivity } from './Activity/hooks' import NFTs from './NFTs' @@ -68,30 +67,30 @@ interface Page { title: React.ReactNode key: string component: ({ account }: { account: string }) => JSX.Element - loggingElementName: string + loggingElementName: InterfaceElementName } const Pages: Array = [ { - title: Tokens, + title: , key: 'tokens', component: Tokens, loggingElementName: InterfaceElementName.MINI_PORTFOLIO_TOKENS_TAB, }, { - title: NFTs, + title: , key: 'nfts', component: NFTs, loggingElementName: InterfaceElementName.MINI_PORTFOLIO_NFT_TAB, }, { - title: Pools, + title: , key: 'pools', component: Pools, loggingElementName: InterfaceElementName.MINI_PORTFOLIO_POOLS_TAB, }, { - title: Activity, + title: , key: 'activity', component: ActivityTab, loggingElementName: InterfaceElementName.MINI_PORTFOLIO_ACTIVITY_TAB, @@ -114,7 +113,9 @@ export default function MiniPortfolio({ account }: { account: string }) { const { hasPendingActivity } = usePendingActivity() useEffect(() => { - if (hasPendingActivity && currentKey !== 'activity') setActivityUnread(true) + if (hasPendingActivity && currentKey !== 'activity') { + setActivityUnread(true) + } }, [currentKey, hasPendingActivity]) return ( @@ -122,20 +123,19 @@ export default function MiniPortfolio({ account }: { account: string }) { diff --git a/apps/web/src/components/AccountDrawer/SettingsMenu.tsx b/apps/web/src/components/AccountDrawer/SettingsMenu.tsx index 6b86406ac6c..24bd9d6a648 100644 --- a/apps/web/src/components/AccountDrawer/SettingsMenu.tsx +++ b/apps/web/src/components/AccountDrawer/SettingsMenu.tsx @@ -83,11 +83,11 @@ export default function SettingsMenu({ const activeLocalCurrency = useActiveLocalCurrency() return ( - Settings} onClose={onClose}> + } onClose={onClose}>
- Preferences + @@ -99,7 +99,7 @@ export default function SettingsMenu({ {!currencyConversionEnabled && ( <> - Language + @@ -108,13 +108,13 @@ export default function SettingsMenu({ {currencyConversionEnabled && ( Language} + title={} currentState={LOCALE_LABEL[activeLocale]} onClick={openLanguageSettings} testId="language-settings-button" /> Currency} + title={} currentState={activeLocalCurrency} onClick={openLocalCurrencySettings} testId="local-currency-settings-button" diff --git a/apps/web/src/components/AccountDrawer/SmallBalanceToggle.tsx b/apps/web/src/components/AccountDrawer/SmallBalanceToggle.tsx index 5384915b85f..267735a1a8d 100644 --- a/apps/web/src/components/AccountDrawer/SmallBalanceToggle.tsx +++ b/apps/web/src/components/AccountDrawer/SmallBalanceToggle.tsx @@ -11,7 +11,7 @@ export function SmallBalanceToggle() { return ( void updateHideSmallBalances((value) => !value)} /> diff --git a/apps/web/src/components/AccountDrawer/SpamToggle.tsx b/apps/web/src/components/AccountDrawer/SpamToggle.tsx index c4296702e41..185d223ac31 100644 --- a/apps/web/src/components/AccountDrawer/SpamToggle.tsx +++ b/apps/web/src/components/AccountDrawer/SpamToggle.tsx @@ -11,7 +11,7 @@ export function SpamToggle() { return ( Hide unknown tokens & NFTs} + title={} isActive={hideSpam} toggle={() => void updateHideSpam((value) => !value)} /> diff --git a/apps/web/src/components/AccountDrawer/TestnetsToggle.tsx b/apps/web/src/components/AccountDrawer/TestnetsToggle.tsx index 8afda983e81..43932697877 100644 --- a/apps/web/src/components/AccountDrawer/TestnetsToggle.tsx +++ b/apps/web/src/components/AccountDrawer/TestnetsToggle.tsx @@ -11,7 +11,7 @@ export function TestnetsToggle() { return ( void updateShowTestnets((value) => !value)} diff --git a/apps/web/src/components/AccountDrawer/UniwalletModal.tsx b/apps/web/src/components/AccountDrawer/UniwalletModal.tsx index cf6ca155117..9283fc05d7d 100644 --- a/apps/web/src/components/AccountDrawer/UniwalletModal.tsx +++ b/apps/web/src/components/AccountDrawer/UniwalletModal.tsx @@ -1,5 +1,4 @@ import { InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' -import { sendAnalyticsEvent } from 'analytics' import Column, { AutoColumn } from 'components/Column' import Modal from 'components/Modal' import { RowBetween } from 'components/Row' @@ -10,6 +9,7 @@ import { QRCodeSVG } from 'qrcode.react' import { useCallback, useEffect, useState } from 'react' import styled, { useTheme } from 'styled-components' import { CloseIcon, ThemedText } from 'theme/components' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { isWebAndroid, isWebIOS } from 'uniswap/src/utils/platform' import { useAccountEffect, useConnect, useDisconnect } from 'wagmi' import uniPng from '../../assets/images/uniwallet_modal_icon.png' @@ -55,7 +55,9 @@ export default function UniwalletModal() { useEffect(() => { function listener({ type, data }: { type: string; data?: unknown }) { - if (type === 'display_uniswap_uri' && typeof data === 'string') setUri(data) + if (type === 'display_uniswap_uri' && typeof data === 'string') { + setUri(data) + } } uniswapWalletConnectConnector.emitter.on('message', listener) @@ -71,7 +73,9 @@ export default function UniwalletModal() { }, [disconnect]) useEffect(() => { - if (open) sendAnalyticsEvent(InterfaceEventName.UNIWALLET_CONNECT_MODAL_OPENED) + if (open) { + sendAnalyticsEvent(InterfaceEventName.UNIWALLET_CONNECT_MODAL_OPENED) + } }, [open]) const theme = useTheme() @@ -80,7 +84,7 @@ export default function UniwalletModal() { - Scan with Uniswap Wallet + @@ -120,10 +124,10 @@ function InfoSection() { - Don't have a Uniswap wallet? + - Safely store and swap tokens with the Uniswap app. Available on iOS and Android. + diff --git a/apps/web/src/components/AccountDrawer/index.tsx b/apps/web/src/components/AccountDrawer/index.tsx index 389fae56e95..488043d5fb7 100644 --- a/apps/web/src/components/AccountDrawer/index.tsx +++ b/apps/web/src/components/AccountDrawer/index.tsx @@ -1,5 +1,4 @@ -import { BrowserEvent, InterfaceEventName } from '@uniswap/analytics-events' -import { TraceEvent } from 'analytics' +import { InterfaceEventName } from '@uniswap/analytics-events' import { ScrollBarStyles } from 'components/Common' import { useWindowSize } from 'hooks/screenSize' import useDisableScrolling from 'hooks/useDisableScrolling' @@ -11,8 +10,8 @@ import styled from 'styled-components' import { BREAKPOINTS } from 'theme' import { ClickableStyle } from 'theme/components' import { Z_INDEX } from 'theme/zIndex' +import Trace from 'uniswap/src/features/telemetry/Trace' import { isMobile } from 'uniswap/src/utils/platform' - import DefaultMenu from './DefaultMenu' import { useAccountDrawer } from './MiniPortfolio/hooks' @@ -51,7 +50,9 @@ export const Scrim = (props: ScrimBackgroundProps) => { const { width } = useWindowSize() useEffect(() => { - if (width && width < BREAKPOINTS.sm && props.$open) document.body.style.overflow = 'hidden' + if (width && width < BREAKPOINTS.sm && props.$open) { + document.body.style.overflow = 'hidden' + } return () => { document.body.style.overflow = 'visible' } @@ -227,15 +228,11 @@ function AccountDrawer() { return ( {walletDrawerOpen && ( - + - + )} diff --git a/apps/web/src/components/AddressInputPanel/index.tsx b/apps/web/src/components/AddressInputPanel/index.tsx index 461154d5c6c..3ddfd467832 100644 --- a/apps/web/src/components/AddressInputPanel/index.tsx +++ b/apps/web/src/components/AddressInputPanel/index.tsx @@ -3,8 +3,8 @@ import { ChangeEvent, ReactNode, useCallback } from 'react' import styled, { useTheme } from 'styled-components' import { ExternalLink, ThemedText } from 'theme/components' import { flexColumnNoWrap } from 'theme/styles' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import useENS from '../../hooks/useENS' import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink' import { AutoColumn } from '../Column' @@ -85,7 +85,7 @@ export default function AddressInputPanel({ // triggers whenever the typed value changes onChange: (value: string) => void }) { - const chainId = useChainId() + const { chainId } = useAccount() const theme = useTheme() const { address, loading, name } = useENS(value) @@ -108,14 +108,14 @@ export default function AddressInputPanel({ - {label ?? Recipient} + {label ?? } {address && chainId && ( - (View on Explorer) + () )} @@ -126,7 +126,7 @@ export default function AddressInputPanel({ autoCorrect="off" autoCapitalize="off" spellCheck="false" - placeholder={placeholder ?? t`Wallet address or ENS name`} + placeholder={placeholder ?? t('common.addressOrENS')} error={error} pattern="^(0x[a-fA-F0-9]{40})$" onChange={handleInput} diff --git a/apps/web/src/components/Badge/RangeBadge.tsx b/apps/web/src/components/Badge/RangeBadge.tsx index dbe74e9c0ba..c3577e23e6e 100644 --- a/apps/web/src/components/Badge/RangeBadge.tsx +++ b/apps/web/src/components/Badge/RangeBadge.tsx @@ -37,40 +37,28 @@ export default function RangeBadge({ removed, inRange }: { removed?: boolean; in return ( {removed ? ( - Your position has 0 liquidity, and is not earning fees.}> + }> - Closed + ) : inRange ? ( - - The price of this pool is within your selected range. Your position is currently earning fees. - - } - > + }> - In range + ) : ( - - The price of this pool is outside of your selected range. Your position is not currently earning fees. - - } - > + }> - Out of range + diff --git a/apps/web/src/components/Banner/Outage/OutageBanner.tsx b/apps/web/src/components/Banner/Outage/OutageBanner.tsx index 1a8aa280ee9..e6d14f48ad6 100644 --- a/apps/web/src/components/Banner/Outage/OutageBanner.tsx +++ b/apps/web/src/components/Banner/Outage/OutageBanner.tsx @@ -56,19 +56,16 @@ export function OutageBanner({ chainId, version }: ChainOutageData) { - {{ versionName }} will be back soon + - - {{ chainName }} - {{ versionDescription }} data is unavailable right now, but we expect the issue to be resolved shortly. - + - You can still swap and provide liquidity on this chain without issue. + - Learn more + Symbol not found + const tokenSymbolName = currency?.symbol ?? const shouldEnableCopy = screenSize['sm'] const shouldShowActions = shouldEnableCopy && hover && !isCopied @@ -98,7 +98,7 @@ export const CurrentPageBreadcrumb = ({ isDisabled={!shouldEnableCopy} onClick={shouldEnableCopy ? copy : undefined} > - + {shortenAddress(address)} {shouldShowActions && ( diff --git a/apps/web/src/components/Button/GetHelp.tsx b/apps/web/src/components/Button/GetHelp.tsx index 06b032d9cfd..00c26dc4b1e 100644 --- a/apps/web/src/components/Button/GetHelp.tsx +++ b/apps/web/src/components/Button/GetHelp.tsx @@ -8,7 +8,7 @@ import { ExternalLink } from 'theme/components' const StyledExternalLink = styled(ExternalLink)` width: fit-content; border-radius: 16px; - padding: 4px 6px; + padding: 4px 8px; font-size: 14px; font-weight: 485; line-height: 20px; @@ -29,7 +29,7 @@ export default function GetHelp() { - Get help + ) diff --git a/apps/web/src/components/Charts/ChartModel.tsx b/apps/web/src/components/Charts/ChartModel.tsx index f5b38006ac5..6654d03b5ee 100644 --- a/apps/web/src/components/Charts/ChartModel.tsx +++ b/apps/web/src/components/Charts/ChartModel.tsx @@ -89,7 +89,9 @@ export abstract class ChartModel { logical !== undefined ) { const item = param.seriesData.get(this.series) as TDataType | undefined - if (item) newHoverData = { item, x, y, logicalIndex: logical } + if (item) { + newHoverData = { item, x, y, logicalIndex: logical } + } } const prevHoverData = this._hoverData @@ -114,7 +116,9 @@ export abstract class ChartModel { protected onSeriesHover(hoverData?: ChartHoverData) { this.onCrosshairMove?.(hoverData?.item, hoverData?.logicalIndex) - if (!hoverData) return + if (!hoverData) { + return + } // Tooltip positioning modified from https://github.com/tradingview/lightweight-charts/blob/master/plugin-examples/src/plugins/tooltip/tooltip.ts const x = hoverData.x + this.api.priceScale('left').width() + 10 @@ -334,7 +338,7 @@ function StaleBanner() { - Data may be outdated + diff --git a/apps/web/src/components/Charts/LiquidityChart/index.tsx b/apps/web/src/components/Charts/LiquidityChart/index.tsx index 1cf8b2f2caf..4670c2de4a9 100644 --- a/apps/web/src/components/Charts/LiquidityChart/index.tsx +++ b/apps/web/src/components/Charts/LiquidityChart/index.tsx @@ -241,7 +241,9 @@ export function useLiquidityBarData({ useEffect(() => { async function formatData() { const ticksProcessed = activePoolData.data - if (!ticksProcessed) return + if (!ticksProcessed) { + return + } let activeRangePercentage: number | undefined = undefined let activeRangeIndex: number | undefined = undefined diff --git a/apps/web/src/components/Charts/LiquidityChart/renderer.tsx b/apps/web/src/components/Charts/LiquidityChart/renderer.tsx index 65636afc515..2c15d8c7587 100644 --- a/apps/web/src/components/Charts/LiquidityChart/renderer.tsx +++ b/apps/web/src/components/Charts/LiquidityChart/renderer.tsx @@ -90,7 +90,9 @@ export class LiquidityBarSeriesRenderer implemen const isCurrentTick = this._options.activeTick === stack.tick const isHoveredTick = this._options.hoveredTick === stack.tick - if (!column) return + if (!column) { + return + } const width = Math.min( Math.max(renderingScope.horizontalPixelRatio, column.right - column.left), this._data.barSpacing * renderingScope.horizontalPixelRatio diff --git a/apps/web/src/components/Charts/LoadingState.tsx b/apps/web/src/components/Charts/LoadingState.tsx index 735fad18232..25229d32c0b 100644 --- a/apps/web/src/components/Charts/LoadingState.tsx +++ b/apps/web/src/components/Charts/LoadingState.tsx @@ -37,7 +37,7 @@ function ChartErrorView({ children }: PropsWithChildren) {
- Missing chart data + {children} diff --git a/apps/web/src/components/Charts/PriceChart/RoundedCandlestickSeries/rounded-candles-series.ts b/apps/web/src/components/Charts/PriceChart/RoundedCandlestickSeries/rounded-candles-series.ts index 8307103ba09..efb2d9b4811 100644 --- a/apps/web/src/components/Charts/PriceChart/RoundedCandlestickSeries/rounded-candles-series.ts +++ b/apps/web/src/components/Charts/PriceChart/RoundedCandlestickSeries/rounded-candles-series.ts @@ -36,7 +36,9 @@ const defaultOptions: RoundedCandleSeriesOptions = { wickUpColor: '#26a69a', wickDownColor: '#ef5350', radius(bs: number) { - if (bs < 4) return 0 + if (bs < 4) { + return 0 + } return bs / 3 }, } as const diff --git a/apps/web/src/components/Charts/PriceChart/index.tsx b/apps/web/src/components/Charts/PriceChart/index.tsx index 0c5900c8a4a..49643b34cb4 100644 --- a/apps/web/src/components/Charts/PriceChart/index.tsx +++ b/apps/web/src/components/Charts/PriceChart/index.tsx @@ -235,19 +235,19 @@ function CandlestickTooltip({ data }: { data: PriceChartData }) { <> - Open +
{formatFiatPrice({ price: data.open })}
- High +
{formatFiatPrice({ price: data.high })}
- Low +
{formatFiatPrice({ price: data.low })}
- Close +
{formatFiatPrice({ price: data.close })}
diff --git a/apps/web/src/components/Charts/PriceChart/utils.ts b/apps/web/src/components/Charts/PriceChart/utils.ts index e5985384550..4835419b3db 100644 --- a/apps/web/src/components/Charts/PriceChart/utils.ts +++ b/apps/web/src/components/Charts/PriceChart/utils.ts @@ -5,7 +5,9 @@ import { CandlestickData } from 'lightweight-charts' * Returns the minimum and maximum values in the given array of PricePoints. */ export function getPriceBounds(prices: PricePoint[]): { min: number; max: number } { - if (!prices.length) return { min: 0, max: 0 } + if (!prices.length) { + return { min: 0, max: 0 } + } let min = prices[0].value let max = prices[0].value @@ -26,7 +28,9 @@ export function getPriceBounds(prices: PricePoint[]): { min: number; max: number * Returns the minimum and maximum values in the given array of candlestick data. */ export function getCandlestickPriceBounds(data: CandlestickData[]): { min: number; max: number } { - if (!data.length) return { min: 0, max: 0 } + if (!data.length) { + return { min: 0, max: 0 } + } let min = data[0].low let max = data[0].high diff --git a/apps/web/src/components/Charts/StackedLineChart/stacked-area-series/renderer.ts b/apps/web/src/components/Charts/StackedLineChart/stacked-area-series/renderer.ts index 05f315dac46..3f570e2945a 100644 --- a/apps/web/src/components/Charts/StackedLineChart/stacked-area-series/renderer.ts +++ b/apps/web/src/components/Charts/StackedLineChart/stacked-area-series/renderer.ts @@ -164,7 +164,9 @@ export class StackedAreaSeriesRenderer implements // Modification: updated loop to include one point above and below the visible range to ensure the line is drawn to edges of chart for (let i = visibleRange.from - 1; i < visibleRange.to + 1; i++) { - if (i >= bars.length || i < 0) continue + if (i >= bars.length || i < 0) { + continue + } const stack = bars[i] let lineIndex = 0 @@ -200,7 +202,9 @@ export class StackedAreaSeriesRenderer implements firstBar = true // Modification: updated loop to include one point above and below the visible range to ensure the line is drawn to edges of chart for (let i = visibleRange.to + 1; i >= visibleRange.from - 1; i--) { - if (i >= bars.length || i < 0) continue + if (i >= bars.length || i < 0) { + continue + } const stack = bars[i] let lineIndex = 0 stack.ys.forEach((yMedia, index) => { diff --git a/apps/web/src/components/Charts/VolumeChart/CrosshairHighlightPrimitive.tsx b/apps/web/src/components/Charts/VolumeChart/CrosshairHighlightPrimitive.tsx index d864e1de32c..580d00f5952 100644 --- a/apps/web/src/components/Charts/VolumeChart/CrosshairHighlightPrimitive.tsx +++ b/apps/web/src/components/Charts/VolumeChart/CrosshairHighlightPrimitive.tsx @@ -64,7 +64,9 @@ class CrosshairHighlightPaneRenderer implements ISeriesPrimitivePaneRenderer { } draw(target: CanvasRenderingTarget2D) { - if (!this._data.visible) return + if (!this._data.visible) { + return + } target.useBitmapCoordinateSpace((scope) => { const ctx = scope.context const crosshairPos = positionsLine(this._data.x, scope.horizontalPixelRatio, Math.max(1, this._data.barSpacing)) @@ -207,10 +209,14 @@ export class CrosshairHighlightPrimitive implements ISeriesPrimitive
- Powered by MoonPay USA LLC + diff --git a/apps/web/src/components/FiatOnrampModal/utils.ts b/apps/web/src/components/FiatOnrampModal/utils.ts index 4b3a7a1309e..fef0144e117 100644 --- a/apps/web/src/components/FiatOnrampModal/utils.ts +++ b/apps/web/src/components/FiatOnrampModal/utils.ts @@ -52,7 +52,9 @@ export function getDefaultCurrencyCode( address: string | undefined, gqlChain?: InterfaceGqlChain ): MoonpaySupportedCurrencyCode { - if (!address || !gqlChain) return 'eth' + if (!address || !gqlChain) { + return 'eth' + } if (isMoonpaySupportedChain(gqlChain)) { const code = CURRENCY_CODES[gqlChain]?.[address.toLowerCase()] return code ?? 'eth' diff --git a/apps/web/src/components/Icons/AlertTriangleFilled.tsx b/apps/web/src/components/Icons/AlertTriangleFilled.tsx index b3329eaca6a..e0d77fcc9a0 100644 --- a/apps/web/src/components/Icons/AlertTriangleFilled.tsx +++ b/apps/web/src/components/Icons/AlertTriangleFilled.tsx @@ -5,14 +5,11 @@ import { StyledSVG } from './shared' export default function AlertTriangleFilled({ size = '16px', ...rest }: { size?: string; [k: string]: any }) { const theme = useTheme() return ( - - + + ) } diff --git a/apps/web/src/components/Identicon/StatusIcon.test.tsx b/apps/web/src/components/Identicon/StatusIcon.test.tsx index 418b8838ddd..50d805a626b 100644 --- a/apps/web/src/components/Identicon/StatusIcon.test.tsx +++ b/apps/web/src/components/Identicon/StatusIcon.test.tsx @@ -1,15 +1,11 @@ import StatusIcon from 'components/Identicon/StatusIcon' +import { useAccount } from 'hooks/useAccount' import { mocked } from 'test-utils/mocked' import { render, waitFor } from 'test-utils/render' -import { useAccount } from 'wagmi' const ACCOUNT = '0x0' -jest.mock('wagmi', () => ({ - ...jest.requireActual('wagmi'), - useAccount: jest.fn(), -})) - +jest.mock('hooks/useAccount') jest.mock('uniswap/src/features/unitags/hooks', () => ({ useUnitagByAddress: () => ({ unitag: undefined, loading: false }), })) diff --git a/apps/web/src/components/Identicon/StatusIcon.tsx b/apps/web/src/components/Identicon/StatusIcon.tsx index cbc8fab116b..c8df637d56b 100644 --- a/apps/web/src/components/Identicon/StatusIcon.tsx +++ b/apps/web/src/components/Identicon/StatusIcon.tsx @@ -1,10 +1,11 @@ import Identicon from 'components/Identicon' import { CONNECTOR_ICON_OVERRIDE_MAP } from 'components/Web3Provider/constants' import { navSearchInputVisibleSize } from 'hooks/screenSize/useScreenSize' +import { useAccount } from 'hooks/useAccount' import { useHasSocks } from 'hooks/useSocksBalance' import styled from 'styled-components' import { flexColumnNoWrap } from 'theme/styles' -import { useAccount } from 'wagmi' + import sockImg from '../../assets/svg/socks.svg' export const IconWrapper = styled.div<{ size?: number }>` @@ -59,7 +60,9 @@ function Socks() { function MiniWalletIcon() { const { connector } = useAccount() - if (!connector) return null + if (!connector) { + return null + } const icon = CONNECTOR_ICON_OVERRIDE_MAP[connector.id] ?? connector.icon diff --git a/apps/web/src/components/Identicon/__snapshots__/StatusIcon.test.tsx.snap b/apps/web/src/components/Identicon/__snapshots__/StatusIcon.test.tsx.snap index eaa2516c4db..a605cb81cba 100644 --- a/apps/web/src/components/Identicon/__snapshots__/StatusIcon.test.tsx.snap +++ b/apps/web/src/components/Identicon/__snapshots__/StatusIcon.test.tsx.snap @@ -1,6 +1,23 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`StatusIcon with account renders children in correct order 1`] = ` +.c1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-animation: iCPeaJ 250ms ease-in-out forwards; + animation: iCPeaJ 250ms ease-in-out forwards; +} + .c0 { position: relative; display: -webkit-box; @@ -26,7 +43,7 @@ exports[`StatusIcon with account renders children in correct order 1`] = ` width: 16px; } -.c1 { +.c2 { position: absolute; display: -webkit-box; display: -webkit-flex; @@ -51,7 +68,7 @@ exports[`StatusIcon with account renders children in correct order 1`] = ` overflow: hidden; } -.c3 { +.c4 { position: absolute; display: -webkit-box; display: -webkit-flex; @@ -76,7 +93,7 @@ exports[`StatusIcon with account renders children in correct order 1`] = ` overflow: hidden; } -.c2 { +.c3 { width: 16px; height: 16px; } @@ -97,13 +114,13 @@ exports[`StatusIcon with account renders children in correct order 1`] = ` } @supports (overflow:clip) { - .c1 { + .c2 { overflow: clip; } } @supports (overflow:clip) { - .c3 { + .c4 { overflow: clip; } } @@ -115,19 +132,22 @@ exports[`StatusIcon with account renders children in correct order 1`] = ` >
+
undefined icon
diff --git a/apps/web/src/components/Identicon/index.tsx b/apps/web/src/components/Identicon/index.tsx index 8fa02d477fb..e4140530642 100644 --- a/apps/web/src/components/Identicon/index.tsx +++ b/apps/web/src/components/Identicon/index.tsx @@ -1,7 +1,9 @@ +import { LoaderV3 } from 'components/Icons/LoadingSpinner' import { UniTagProfilePicture } from 'components/UniTag/UniTagProfilePicture' import { Unicon } from 'components/Unicon' import useENSAvatar from 'hooks/useENSAvatar' -import { Loader } from 'react-feather' +import styled from 'styled-components' +import { fadeInAnimation } from 'theme/components/FadePresence' import { UniconV2 } from 'ui/src/components/UniconV2' import { FeatureFlags } from 'uniswap/src/features/gating/flags' import { useFeatureFlag } from 'uniswap/src/features/gating/hooks' @@ -21,7 +23,9 @@ export function useIdenticonType(account?: string) { const { avatar, loading: ensAvatarLoading } = useENSAvatar(account) const uniconV2Enabled = useFeatureFlag(FeatureFlags.UniconsV2) - if (!account) return undefined + if (!account) { + return undefined + } if (unitagLoading || ensAvatarLoading) { return IdenticonType.LOADING } else if (unitag?.metadata?.avatar) { @@ -33,21 +37,46 @@ export function useIdenticonType(account?: string) { } } +const FadeInContainer = styled.div` + display: flex; + align-items: center; + justify-content: center; + ${fadeInAnimation} +` + export default function Identicon({ account, size }: { account?: string; size: number }) { const identiconType = useIdenticonType(account) - if (!account) return null + if (!account) { + return null + } switch (identiconType) { case IdenticonType.LOADING: - return + return case IdenticonType.UNITAG_PROFILE_PICTURE: - return + return ( + + + + ) case IdenticonType.ENS_AVATAR: - return + return ( + + + + ) case IdenticonType.UNICON_V2: - return + return ( + + + + ) case IdenticonType.UNICON: - return + return ( + + + + ) default: return null } diff --git a/apps/web/src/components/InputStepCounter/InputStepCounter.tsx b/apps/web/src/components/InputStepCounter/InputStepCounter.tsx index 88e3cb23f44..041944b8b79 100644 --- a/apps/web/src/components/InputStepCounter/InputStepCounter.tsx +++ b/apps/web/src/components/InputStepCounter/InputStepCounter.tsx @@ -157,9 +157,7 @@ const StepCounter = ({ }} /> - - {{ tokenB }} per {{ tokenA }} - + diff --git a/apps/web/src/components/LiquidityChartRangeInput/Brush.tsx b/apps/web/src/components/LiquidityChartRangeInput/Brush.tsx index 659f8bf90ce..df21b707c7f 100644 --- a/apps/web/src/components/LiquidityChartRangeInput/Brush.tsx +++ b/apps/web/src/components/LiquidityChartRangeInput/Brush.tsx @@ -116,7 +116,9 @@ export const Brush = ({ // initialize the brush useEffect(() => { - if (!brushRef.current) return + if (!brushRef.current) { + return + } brushBehavior.current = brushX() .extent([ @@ -145,7 +147,9 @@ export const Brush = ({ // respond to xScale changes only useEffect(() => { - if (!brushRef.current || !brushBehavior.current) return + if (!brushRef.current || !brushBehavior.current) { + return + } brushBehavior.current.move(select(brushRef.current) as any, brushExtent.map(xScale) as any) }, [brushExtent, xScale]) diff --git a/apps/web/src/components/LiquidityChartRangeInput/Zoom.tsx b/apps/web/src/components/LiquidityChartRangeInput/Zoom.tsx index f588373f98d..8da92efd87f 100644 --- a/apps/web/src/components/LiquidityChartRangeInput/Zoom.tsx +++ b/apps/web/src/components/LiquidityChartRangeInput/Zoom.tsx @@ -89,7 +89,9 @@ export default function Zoom({ ) useEffect(() => { - if (!svg) return + if (!svg) { + return + } zoomBehavior.current = zoom() .scaleExtent([zoomLevels.min, zoomLevels.max]) diff --git a/apps/web/src/components/LiquidityChartRangeInput/index.tsx b/apps/web/src/components/LiquidityChartRangeInput/index.tsx index 857550d580e..f6432f85221 100644 --- a/apps/web/src/components/LiquidityChartRangeInput/index.tsx +++ b/apps/web/src/components/LiquidityChartRangeInput/index.tsx @@ -145,10 +145,16 @@ export default function LiquidityChartRangeInput({ const { formatDelta } = useFormatter() const brushLabelValue = useCallback( (d: 'w' | 'e', x: number) => { - if (!price) return '' + if (!price) { + return '' + } - if (d === 'w' && ticksAtLimit[isSorted ? Bound.LOWER : Bound.UPPER]) return '0' - if (d === 'e' && ticksAtLimit[isSorted ? Bound.UPPER : Bound.LOWER]) return '∞' + if (d === 'w' && ticksAtLimit[isSorted ? Bound.LOWER : Bound.UPPER]) { + return '0' + } + if (d === 'e' && ticksAtLimit[isSorted ? Bound.UPPER : Bound.LOWER]) { + return '∞' + } const percent = (x < price ? -1 : 1) * ((Math.max(x, price) - Math.min(x, price)) / price) * 100 @@ -162,20 +168,17 @@ export default function LiquidityChartRangeInput({ return ( {isUninitialized ? ( - Your position will appear here.} - icon={} - /> + } icon={} /> ) : isLoading ? ( } /> ) : error ? ( Liquidity data not available.} + message={} icon={} /> ) : !formattedData || formattedData.length === 0 || !price ? ( There is no liquidity data.} + message={} icon={} /> ) : ( diff --git a/apps/web/src/components/Logo/ChainLogo.tsx b/apps/web/src/components/Logo/ChainLogo.tsx index 51e01009d07..6669d7483df 100644 --- a/apps/web/src/components/Logo/ChainLogo.tsx +++ b/apps/web/src/components/Logo/ChainLogo.tsx @@ -1,5 +1,5 @@ import { ChainId } from '@uniswap/sdk-core' -import { SupportedInterfaceChainId, getChainInfo, useIsSupportedChainId } from 'constants/chains' +import { SupportedInterfaceChainId, getChain, useIsSupportedChainId } from 'constants/chains' import { CSSProperties, FunctionComponent } from 'react' import { useTheme } from 'styled-components' import { useIsDarkMode } from 'theme/components/ThemeToggle' @@ -123,8 +123,10 @@ export function ChainLogo({ const { surface2 } = useTheme() const isSupportedChain = useIsSupportedChainId(chainId) - if (!isSupportedChain) return null - const { label } = getChainInfo({ chainId }) + if (!isSupportedChain) { + return null + } + const { label } = getChain({ chainId }) const { Symbol, bgColor } = getChainUI(chainId, darkMode) const iconSize = fillContainer ? '100%' : size diff --git a/apps/web/src/components/Logo/HolidayUniIcon.tsx b/apps/web/src/components/Logo/HolidayUniIcon.tsx index 89d2b461e70..40dfbbb0d70 100644 --- a/apps/web/src/components/Logo/HolidayUniIcon.tsx +++ b/apps/web/src/components/Logo/HolidayUniIcon.tsx @@ -5,7 +5,7 @@ import { ReactComponent as WinterUni } from '../../assets/svg/winter-uni.svg' import { SVGProps } from './UniIcon' const MONTH_TO_HOLIDAY_UNI: { [date: string]: (props: SVGProps) => ReactElement } = { - '12': (props) => , + '12': (props) => , '1': (props) => , } diff --git a/apps/web/src/components/Logo/UniswapXBrandMark.tsx b/apps/web/src/components/Logo/UniswapXBrandMark.tsx index 73adffac97e..4993157f9a1 100644 --- a/apps/web/src/components/Logo/UniswapXBrandMark.tsx +++ b/apps/web/src/components/Logo/UniswapXBrandMark.tsx @@ -16,7 +16,7 @@ export default function UniswapXBrandMark({ fontWeight, ...props }: UniswapXBran fontWeight: 535, })} > - UniswapX + ) diff --git a/apps/web/src/components/ModalViews/index.tsx b/apps/web/src/components/ModalViews/index.tsx index 573c2908aa4..57b10fc7d73 100644 --- a/apps/web/src/components/ModalViews/index.tsx +++ b/apps/web/src/components/ModalViews/index.tsx @@ -2,8 +2,8 @@ import { Trans } from 'i18n' import { ArrowUpCircle } from 'react-feather' import styled, { useTheme } from 'styled-components' import { CloseIcon, CustomLightSpinner, ThemedText } from 'theme/components' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import Circle from '../../assets/images/blue-loader.svg' import { ExternalLink } from '../../theme/components' import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink' @@ -32,7 +32,7 @@ export function LoadingView({ children, onDismiss }: { children: any; onDismiss: {children} - Confirm this transaction in your wallet + @@ -41,7 +41,7 @@ export function LoadingView({ children, onDismiss }: { children: any; onDismiss: export function SubmittedView({ children, onDismiss, hash }: { children: any; onDismiss: () => void; hash?: string }) { const theme = useTheme() - const chainId = useChainId() + const { chainId } = useAccount() return ( @@ -60,7 +60,7 @@ export function SubmittedView({ children, onDismiss, hash }: { children: any; on style={{ marginLeft: '4px' }} > - View transaction on Explorer + )} diff --git a/apps/web/src/components/NavBar/ChainSelector.tsx b/apps/web/src/components/NavBar/ChainSelector.tsx index 12aa7a74ec6..b54e492e41f 100644 --- a/apps/web/src/components/NavBar/ChainSelector.tsx +++ b/apps/web/src/components/NavBar/ChainSelector.tsx @@ -3,14 +3,7 @@ import { showTestnetsAtom } from 'components/AccountDrawer/TestnetsToggle' import { DropdownSelector, StyledMenuContent } from 'components/DropdownSelector' import { ChainLogo } from 'components/Logo/ChainLogo' import { CONNECTION } from 'components/Web3Provider/constants' -import { WalletConnectConnector } from 'components/Web3Provider/walletConnect' -import { - L1_CHAIN_IDS, - L2_CHAIN_IDS, - TESTNET_CHAIN_IDS, - getChainPriority, - useIsSupportedChainId, -} from 'constants/chains' +import { L1_CHAIN_IDS, L2_CHAIN_IDS, TESTNET_CHAIN_IDS, getChainPriority } from 'constants/chains' import useSelectChain from 'hooks/useSelectChain' import useSyncChainQuery from 'hooks/useSyncChainQuery' import { t } from 'i18n' @@ -18,8 +11,9 @@ import { useAtomValue } from 'jotai/utils' import { useCallback, useMemo, useState } from 'react' import { AlertTriangle } from 'react-feather' import { css, useTheme } from 'styled-components' -import { useAccount, useChainId } from 'wagmi' +import { Connector } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import ChainSelectorRow from './ChainSelectorRow' const NETWORK_SELECTOR_CHAINS = [...L1_CHAIN_IDS, ...L2_CHAIN_IDS] @@ -42,6 +36,11 @@ const styledMobileMenuCss = css` } ` +type WalletConnectConnector = Connector & { + type: typeof CONNECTION.UNISWAP_WALLET_CONNECT_CONNECTOR_ID + getNamespaceChainsIds: () => ChainId[] +} + function useWalletSupportedChains(): ChainId[] { const { connector } = useAccount() @@ -58,10 +57,7 @@ function useWalletSupportedChains(): ChainId[] { } export const ChainSelector = ({ leftAlign }: { leftAlign?: boolean }) => { - const disconnectedChainId = useChainId() - const account = useAccount() - const chainId = account?.chainId ?? disconnectedChainId - const isSupportedChain = useIsSupportedChainId(chainId) + const { chainId } = useAccount() const [isOpen, setIsOpen] = useState(false) const theme = useTheme() @@ -103,10 +99,6 @@ export const ChainSelector = ({ leftAlign }: { leftAlign?: boolean }) => { [selectChain, setIsOpen] ) - if (!chainId) { - return null - } - const styledMenuCss = css` ${leftAlign ? 'left: 0;' : 'right: 0;'} ${styledMobileMenuCss}; @@ -117,13 +109,13 @@ export const ChainSelector = ({ leftAlign }: { leftAlign?: boolean }) => { isOpen={isOpen} toggleOpen={() => setIsOpen(!isOpen)} menuLabel={ - !isSupportedChain ? ( + !chainId ? ( ) : ( ) } - tooltipText={isSupportedChain ? undefined : t`Your wallet's current network is unsupported.`} + tooltipText={chainId ? undefined : t('wallet.networkUnsupported')} dataTestId="chain-selector" optionsContainerTestId="chain-selector-options" internalMenuItems={ diff --git a/apps/web/src/components/NavBar/ChainSelectorRow.tsx b/apps/web/src/components/NavBar/ChainSelectorRow.tsx index a217e5a65c4..a024ac26028 100644 --- a/apps/web/src/components/NavBar/ChainSelectorRow.tsx +++ b/apps/web/src/components/NavBar/ChainSelectorRow.tsx @@ -1,13 +1,13 @@ -import { BrowserEvent, SharedEventName } from '@uniswap/analytics-events' import { ChainId } from '@uniswap/sdk-core' -import { TraceEvent } from 'analytics' import Loader from 'components/Icons/LoadingSpinner' import { ChainLogo } from 'components/Logo/ChainLogo' -import { getChainInfo, useSupportedChainId } from 'constants/chains' +import { getChain, useSupportedChainId } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import { Trans } from 'i18n' import { CheckMarkIcon } from 'nft/components/icons' import styled, { useTheme } from 'styled-components' -import { useChainId } from 'wagmi' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { SectionName } from 'uniswap/src/features/telemetry/constants' const LOGO_SIZE = 20 @@ -64,32 +64,35 @@ interface ChainSelectorRowProps { isPending: boolean } export default function ChainSelectorRow({ disabled, targetChain, onSelectChain, isPending }: ChainSelectorRowProps) { - const chainId = useChainId() + const theme = useTheme() + const { chainId } = useAccount() const supportedChain = useSupportedChainId(targetChain) const active = chainId === targetChain - const label = getChainInfo({ chainId: supportedChain })?.label - const theme = useTheme() + const chainInfo = getChain({ chainId: supportedChain }) + const label = chainInfo?.label return ( - + { - if (!disabled) onSelectChain(targetChain) + if (!disabled) { + onSelectChain(targetChain) + } }} > {label && } {disabled && ( - Unsupported by your wallet + )} {isPending && ( - Approve in wallet + )} @@ -97,6 +100,6 @@ export default function ChainSelectorRow({ disabled, targetChain, onSelectChain, {!active && isPending && } - + ) } diff --git a/apps/web/src/components/NavBar/MobileAppPromoBanner.tsx b/apps/web/src/components/NavBar/MobileAppPromoBanner.tsx new file mode 100644 index 00000000000..e7b4ec3b048 --- /dev/null +++ b/apps/web/src/components/NavBar/MobileAppPromoBanner.tsx @@ -0,0 +1,129 @@ +import { ReactComponent as UniswapLogo } from 'assets/svg/uniswap_app_logo.svg' +import Column from 'components/Column' +import Row from 'components/Row' +import { useEthersWeb3Provider } from 'hooks/useEthersProvider' +import { useAtom } from 'jotai' +import { useAtomValue } from 'jotai/utils' +import { useState } from 'react' +import { X } from 'react-feather' +import { Trans } from 'react-i18next' +import { hideMobileAppPromoBannerAtom } from 'state/application/atoms' +import styled, { useTheme } from 'styled-components' +import { BREAKPOINTS } from 'theme' +import { ThemedText } from 'theme/components' +import { Z_INDEX } from 'theme/zIndex' +import { isWebAndroid, isWebIOS } from 'uniswap/src/utils/platform' +import { getWalletMeta } from 'utils/walletMeta' + +const Wrapper = styled.div` + height: 56px; + width: 100%; + background-color: ${({ theme }) => theme.accent2}; + padding: 10px 16px 10px 12px; + z-index: ${Z_INDEX.sticky}; + flex-direction: row; + justify-content: space-between; + align-items: center; + + display: none; + @media screen and (max-width: ${BREAKPOINTS.sm}px) { + display: flex; + } +` + +const StyledButton = styled.a` + height: 28px; + background: ${({ theme }) => theme.accent1}; + border-radius: 16px; + padding: 8px; + display: flex; + justify-content: center; + align-items: center; + white-space: nowrap; +` + +/** + * We show the mobile app promo banner if: + * - The user is on a mobile device our app supports + * - The user is not using Safari (since we don't want to conflict with the Safari-native Smart App Banner) + * - The user has not dismissed the banner during this session + */ +export function useMobileAppPromoBannerEligible() { + const hideMobileAppPromoBanner = useAtomValue(hideMobileAppPromoBannerAtom) + return (isWebIOS || isWebAndroid) && !hideMobileAppPromoBanner +} + +const UNIVERSAL_DOWNLOAD_LINK = 'https://uniswapwallet.onelink.me/8q3y/39b0eeui' + +function getDownloadLink(userAgent: string, peerWalletAgent?: string): string { + if (userAgent.includes('MetaMaskMobile')) { + return 'https://uniswapwallet.onelink.me/8q3y/ee713xnh' + } + if (userAgent.includes('Phantom')) { + return 'https://uniswapwallet.onelink.me/8q3y/sjdi6xky' + } + if (userAgent.includes('OKApp')) { + return 'https://uniswapwallet.onelink.me/8q3y/7i8g60sb' + } + if (userAgent.includes('BitKeep')) { + return 'https://uniswapwallet.onelink.me/8q3y/93vro3iq' + } + if (userAgent.includes('DeFiWallet')) { + return 'https://uniswapwallet.onelink.me/8q3y/ay1z22ab' + } + if (userAgent.includes('1inchWallet')) { + return 'https://uniswapwallet.onelink.me/8q3y/03e2c5cw' + } + if (userAgent.includes('RHNCW')) { + return 'https://uniswapwallet.onelink.me/8q3y/ipq1dx4n' + } + if (peerWalletAgent?.includes('CoinbaseWallet CoinbaseBrowser')) { + return 'https://uniswapwallet.onelink.me/8q3y/24xpl5zh' + } + return UNIVERSAL_DOWNLOAD_LINK +} + +export function MobileAppPromoBanner() { + const [isVisible, setIsVisible] = useState(true) + const theme = useTheme() + const mobileAppPromoBannerEligible = useMobileAppPromoBannerEligible() + const [, setHideMobileAppPromoBanner] = useAtom(hideMobileAppPromoBannerAtom) + + const provider = useEthersWeb3Provider() + + const peerWalletAgent = provider ? getWalletMeta(provider)?.agent : undefined + + if (!mobileAppPromoBannerEligible || !isVisible) { + return null + } + + return ( + + + { + setIsVisible(false) + setHideMobileAppPromoBanner(true) + }} + /> + + + + Uniswap: Crypto & NFT Wallet + + + Get the Uniswap Wallet app + + + + + + Get app + + + + ) +} diff --git a/apps/web/src/components/NavBar/More/Menu.tsx b/apps/web/src/components/NavBar/More/Menu.tsx index 017232b32aa..3a1dbfc1314 100644 --- a/apps/web/src/components/NavBar/More/Menu.tsx +++ b/apps/web/src/components/NavBar/More/Menu.tsx @@ -124,10 +124,10 @@ export function Menu({ close }: { close: () => void }) { - Download Uniswap + - Available on iOS and Android + diff --git a/apps/web/src/components/NavBar/NavIcon.tsx b/apps/web/src/components/NavBar/NavIcon.tsx index bc9cff9a30c..5c13a160f80 100644 --- a/apps/web/src/components/NavBar/NavIcon.tsx +++ b/apps/web/src/components/NavBar/NavIcon.tsx @@ -15,7 +15,7 @@ interface NavIconProps { export const NavIcon = ({ children, isActive, - label = t`Navigation button`, + label = t('common.navigationButton'), onClick, activeBackground, }: NavIconProps) => { diff --git a/apps/web/src/components/NavBar/RecentlySearchedAssets.ts b/apps/web/src/components/NavBar/RecentlySearchedAssets.ts index a662d9dc782..cff09ab03e9 100644 --- a/apps/web/src/components/NavBar/RecentlySearchedAssets.ts +++ b/apps/web/src/components/NavBar/RecentlySearchedAssets.ts @@ -59,8 +59,11 @@ export function useRecentlySearchedAssets() { }) const data = useMemo(() => { - if (shortenedHistory.length === 0) return [] - else if (!queryData) return undefined + if (shortenedHistory.length === 0) { + return [] + } else if (!queryData) { + return undefined + } // Collects both tokens and collections in a map, so they can later be returned in original order const resultsMap: { [key: string]: GenieCollection | SearchToken } = {} @@ -102,10 +105,14 @@ export function useRecentlySearchedAssets() { const native = nativeOnChain(chain) const queryAddress = getQueryAddress(asset.chain)?.toLowerCase() ?? `NATIVE-${asset.chain}` const result = resultsMap[queryAddress] - if (result) data.push({ ...result, address: NATIVE_CHAIN_ID, ...native }) + if (result) { + data.push({ ...result, address: NATIVE_CHAIN_ID, ...native }) + } } else { const result = resultsMap[asset.address] - if (result) data.push(result) + if (result) { + data.push(result) + } } }) return data diff --git a/apps/web/src/components/NavBar/SearchBar.tsx b/apps/web/src/components/NavBar/SearchBar.tsx index 8cc387d73c9..316c3f84e79 100644 --- a/apps/web/src/components/NavBar/SearchBar.tsx +++ b/apps/web/src/components/NavBar/SearchBar.tsx @@ -1,15 +1,16 @@ // eslint-disable-next-line no-restricted-imports -import { BrowserEvent, InterfaceElementName, InterfaceEventName, InterfaceSectionName } from '@uniswap/analytics-events' -import { Trace, TraceEvent, sendAnalyticsEvent, useTrace } from 'analytics' +import { InterfaceElementName, InterfaceEventName, InterfaceSectionName } from '@uniswap/analytics-events' import clsx from 'clsx' import { Search } from 'components/Icons/Search' import { useSearchTokens } from 'graphql/data/SearchTokens' import { useCollectionSearch } from 'graphql/data/nft/CollectionSearch' +import { useIsMobile, useIsTablet } from 'hooks/screenSize' +import { useAccount } from 'hooks/useAccount' import useDebounce from 'hooks/useDebounce' import { useDisableNFTRoutes } from 'hooks/useDisableNFTRoutes' import { useIsNftPage } from 'hooks/useIsNftPage' import { useOnClickOutside } from 'hooks/useOnClickOutside' -import { useTranslation } from 'i18n' +import { useTranslation } from 'i18n/useTranslation' import { organizeSearchResults } from 'lib/utils/searchBar' import { Box } from 'nft/components/Box' import { Column, Row } from 'nft/components/Flex' @@ -18,9 +19,9 @@ import { useIsNavSearchInputVisible } from 'nft/hooks/useIsNavSearchInputVisible import { ChangeEvent, useCallback, useEffect, useReducer, useRef, useState } from 'react' import { useLocation } from 'react-router-dom' import styled from 'styled-components' -import { useChainId } from 'wagmi' - -import { useIsMobile, useIsTablet } from 'hooks/screenSize' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { ChevronLeftIcon, NavMagnifyingGlassIcon } from '../../nft/components/icons' import { NavIcon } from './NavIcon' import * as styles from './SearchBar.css' @@ -44,7 +45,7 @@ const KeyShortCut = styled.div` export const SearchBar = () => { const [isOpen, toggleOpen] = useReducer((state: boolean) => !state, false) - const [searchValue, setSearchValue] = useState('') + const [searchValue, setSearchValue] = useState('') const debouncedSearchValue = useDebounce(searchValue, 300) const searchRef = useRef(null) const inputRef = useRef(null) @@ -60,7 +61,7 @@ export const SearchBar = () => { const { data: collections, loading: collectionsAreLoading } = useCollectionSearch(debouncedSearchValue) - const chainId = useChainId() + const { chainId } = useAccount() const { data: tokens, loading: tokensAreLoading } = useSearchTokens(debouncedSearchValue, chainId ?? 1) const isNFTPage = useIsNftPage() @@ -101,16 +102,16 @@ export const SearchBar = () => { const navbarSearchEventProperties = { navbar_search_input_text: debouncedSearchValue, - hasInput: debouncedSearchValue && debouncedSearchValue.length > 0, + hasInput: debouncedSearchValue.length > 0, ...trace, } const { t } = useTranslation() // subscribe to locale changes const placeholderText = isMobileOrTablet - ? t`Search` + ? t('common.search.label') : shouldDisableNFTRoutes - ? t`Search tokens` - : t`Search tokens and NFT collections` + ? t('common.searchTokens') + : t('common.searchTokensNFT') const handleKeyPress = useCallback( (event: any) => { @@ -177,9 +178,9 @@ export const SearchBar = () => { - @@ -197,7 +198,7 @@ export const SearchBar = () => { ref={inputRef} width="full" /> - + {!isOpen && /} diff --git a/apps/web/src/components/NavBar/SearchBarDropdown.tsx b/apps/web/src/components/NavBar/SearchBarDropdown.tsx index 6a99cb710e1..c1f82501b35 100644 --- a/apps/web/src/components/NavBar/SearchBarDropdown.tsx +++ b/apps/web/src/components/NavBar/SearchBarDropdown.tsx @@ -1,7 +1,6 @@ import { InterfaceSectionName, NavBarSearchTypes } from '@uniswap/analytics-events' import { ChainId } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' -import { useTrace } from 'analytics' import clsx from 'clsx' import Badge from 'components/Badge' import { ChainLogo } from 'components/Logo/ChainLogo' @@ -9,6 +8,7 @@ import { BACKEND_NOT_YET_SUPPORTED_CHAIN_IDS } from 'constants/chains' import { SearchToken } from 'graphql/data/SearchTokens' import useTrendingTokens from 'graphql/data/TrendingTokens' import { useTrendingCollections } from 'graphql/data/nft/TrendingCollections' +import { useAccount } from 'hooks/useAccount' import { useDisableNFTRoutes } from 'hooks/useDisableNFTRoutes' import { useIsNftPage } from 'hooks/useIsNftPage' import { Trans } from 'i18n' @@ -21,8 +21,8 @@ import { useLocation } from 'react-router-dom' import styled from 'styled-components' import { ThemedText } from 'theme/components' import { HistoryDuration, SafetyLevel } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' -import { useChainId } from 'wagmi' - +import { InterfaceSearchResultSelectionProperties } from 'uniswap/src/features/telemetry/types' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { ClockIcon, TrendingArrow } from '../../nft/components/icons' import { SuspendConditionally } from '../Suspense/SuspendConditionally' import { SuspenseWithPreviousRenderAsFallback } from '../Suspense/SuspenseWithPreviousRenderAsFallback' @@ -39,7 +39,7 @@ interface SearchBarDropdownSectionProps { startingIndex: number setHoveredIndex: (index: number | undefined) => void isLoading?: boolean - eventProperties: Record + eventProperties: InterfaceSearchResultSelectionProperties } const SearchBarDropdownSection = ({ @@ -72,10 +72,10 @@ const SearchBarDropdownSection = ({ toggleOpen={toggleOpen} index={index + startingIndex} eventProperties={{ + ...eventProperties, position: index + startingIndex, selected_search_result_name: suggestion.name, selected_search_result_address: suggestion.address, - ...eventProperties, }} /> ) @@ -114,7 +114,7 @@ interface SearchBarDropdownProps { export const SearchBarDropdown = (props: SearchBarDropdownProps) => { const { isLoading } = props - const chainId = useChainId() + const { chainId } = useAccount() const showChainComingSoonBadge = chainId && BACKEND_NOT_YET_SUPPORTED_CHAIN_IDS.includes(chainId) && !isLoading return ( @@ -220,12 +220,12 @@ function SearchBarDropdownContents({ const hasKnownToken = tokens.some(isKnownToken) const showCollectionsFirst = isNFTPage && (hasVerifiedCollection || !hasKnownToken) - const trace = JSON.stringify(useTrace({ section: InterfaceSectionName.NAVBAR_SEARCH })) + const trace = useTrace({ section: InterfaceSectionName.NAVBAR_SEARCH }) const eventProperties = { total_suggestions: totalSuggestions, query_text: queryText, - ...JSON.parse(trace), + ...trace, } const tokenSearchResults = @@ -240,11 +240,11 @@ function SearchBarDropdownContents({ suggestion_type: NavBarSearchTypes.TOKEN_SUGGESTION, ...eventProperties, }} - header={Tokens} + header={} /> ) : ( - No tokens found. + ) @@ -260,7 +260,7 @@ function SearchBarDropdownContents({ suggestion_type: NavBarSearchTypes.COLLECTION_SUGGESTION, ...eventProperties, }} - header={NFT collections} + header={} /> ) : ( No NFT collections found. @@ -295,7 +295,7 @@ function SearchBarDropdownContents({ suggestion_type: NavBarSearchTypes.RECENT_SEARCH, ...eventProperties, }} - header={Recent searches} + header={} headerIcon={} isLoading={!searchHistory} /> @@ -311,7 +311,7 @@ function SearchBarDropdownContents({ suggestion_type: NavBarSearchTypes.TOKEN_TRENDING, ...eventProperties, }} - header={Popular tokens} + header={} headerIcon={} isLoading={!trendingTokenData} /> @@ -327,7 +327,7 @@ function SearchBarDropdownContents({ suggestion_type: NavBarSearchTypes.COLLECTION_TRENDING, ...eventProperties, }} - header={Popular NFT collections} + header={} headerIcon={} isLoading={trendingCollectionsAreLoading} /> @@ -339,7 +339,7 @@ function SearchBarDropdownContents({ function ComingSoonText({ chainId }: { chainId: ChainId }) { switch (chainId) { case ChainId.AVALANCHE: - return Coming soon: search and explore tokens on Avalanche Chain + return default: return null } diff --git a/apps/web/src/components/NavBar/SuggestionRow.tsx b/apps/web/src/components/NavBar/SuggestionRow.tsx index 0f49774dbb7..4e75facec95 100644 --- a/apps/web/src/components/NavBar/SuggestionRow.tsx +++ b/apps/web/src/components/NavBar/SuggestionRow.tsx @@ -1,10 +1,16 @@ import { InterfaceEventName } from '@uniswap/analytics-events' import { ChainId } from '@uniswap/sdk-core' -import { sendAnalyticsEvent } from 'analytics' +import Column from 'components/Column' import QueryTokenLogo from 'components/Logo/QueryTokenLogo' +import Row from 'components/Row' import TokenSafetyIcon from 'components/TokenSafety/TokenSafetyIcon' +import { DeltaArrow, DeltaText } from 'components/Tokens/TokenDetails/Delta' +import { LoadingBubble } from 'components/Tokens/loading' +import { useTokenWarning } from 'constants/tokenSafety' +import { NATIVE_CHAIN_ID } from 'constants/tokens' import { SearchToken } from 'graphql/data/SearchTokens' import { getTokenDetailsURL, supportedChainIdFromGQLChain } from 'graphql/data/util' +import { Trans } from 'i18n' import { VerifiedIcon } from 'nft/components/icons' import { GenieCollection } from 'nft/types' import { useCallback, useEffect, useState } from 'react' @@ -12,15 +18,9 @@ import { Link, useNavigate } from 'react-router-dom' import styled, { css } from 'styled-components' import { EllipsisStyle, ThemedText } from 'theme/components' import { Chain, TokenStandard } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { InterfaceSearchResultSelectionProperties } from 'uniswap/src/features/telemetry/types' import { NumberType, useFormatter } from 'utils/formatNumbers' - -import Column from 'components/Column' -import Row from 'components/Row' -import { DeltaArrow, DeltaText } from 'components/Tokens/TokenDetails/Delta' -import { LoadingBubble } from 'components/Tokens/loading' -import { useTokenWarning } from 'constants/tokenSafety' -import { NATIVE_CHAIN_ID } from 'constants/tokens' -import { Trans } from 'i18n' import { useAddRecentlySearchedAsset } from './RecentlySearchedAssets' const PriceChangeContainer = styled.div` @@ -82,7 +82,7 @@ interface SuggestionRowProps { setHoveredIndex: (index: number | undefined) => void toggleOpen: () => void index: number - eventProperties: Record + eventProperties: InterfaceSearchResultSelectionProperties } function suggestionIsToken(suggestion: GenieCollection | SearchToken): suggestion is SearchToken { @@ -172,7 +172,7 @@ export const SuggestionRow = ({ ) : ( <> {formatNumberOrString({ input: suggestion?.stats?.total_supply, type: NumberType.WholeNumber })}  - items + )} @@ -200,7 +200,7 @@ export const SuggestionRow = ({ ) : ( - Floor + )} diff --git a/apps/web/src/components/NavBar/UkBanner.tsx b/apps/web/src/components/NavBar/UkBanner.tsx index 0f3312445cc..ab483a306dc 100644 --- a/apps/web/src/components/NavBar/UkBanner.tsx +++ b/apps/web/src/components/NavBar/UkBanner.tsx @@ -1,4 +1,4 @@ -import { t, Trans } from 'i18n' +import { Trans, t } from 'i18n' import { useOpenModal } from 'state/application/hooks' import { ApplicationModal } from 'state/application/reducer' import styled from 'styled-components' @@ -58,23 +58,17 @@ const ReadMoreWrapper = styled(ButtonText)` } ` -export const bannerText = t` - This web application is provided as a tool for users to interact with the Uniswap Protocol on - their own initiative, with no endorsement or recommendation of cryptocurrency trading activities. In doing so, - Uniswap is not recommending that users or potential users engage in cryptoasset trading activity, and users or - potential users of the web application should not regard this webpage or its contents as involving any form of - recommendation, invitation or inducement to deal in cryptoassets. -` +export const bannerText = t('notice.uk') export function UkBanner() { const openDisclaimer = useOpenModal(ApplicationModal.UK_DISCLAIMER) return ( - {t`UK disclaimer:` + ' ' + bannerText} + {t('notice.uk.label') + ' ' + bannerText} - Read more + diff --git a/apps/web/src/components/NavBar/UkDisclaimerModal.tsx b/apps/web/src/components/NavBar/UkDisclaimerModal.tsx index e75016db9b3..21ec7ad66d4 100644 --- a/apps/web/src/components/NavBar/UkDisclaimerModal.tsx +++ b/apps/web/src/components/NavBar/UkDisclaimerModal.tsx @@ -45,7 +45,7 @@ export function UkDisclaimerModal() { - Disclaimer for UK residents + {bannerText} @@ -53,7 +53,7 @@ export function UkDisclaimerModal() { closeModal()}> - Dismiss + diff --git a/apps/web/src/components/NavBar/index.tsx b/apps/web/src/components/NavBar/index.tsx index fd042e1e007..758aaa110ad 100644 --- a/apps/web/src/components/NavBar/index.tsx +++ b/apps/web/src/components/NavBar/index.tsx @@ -18,8 +18,8 @@ import { NavLink, NavLinkProps, useLocation, useNavigate } from 'react-router-do import styled from 'styled-components' import { Z_INDEX } from 'theme/zIndex' import { Chain } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import { useIsNavSearchInputVisible } from '../../nft/hooks/useIsNavSearchInputVisible' import { Bag } from './Bag' import Blur from './Blur' @@ -59,7 +59,7 @@ const MenuItem = ({ href, dataTestId, id, isActive, children }: MenuItemProps) = export const PageTabs = () => { const { pathname } = useLocation() - const chainId = useChainId() + const { chainId } = useAccount() const chainName = chainIdToBackendChain({ chainId, withFallback: true }) const isPoolActive = useIsPoolsPage() @@ -70,22 +70,22 @@ export const PageTabs = () => { return ( <> - Swap + - Explore + {!shouldDisableNFTRoutes && ( - NFTs + )} - Pool + diff --git a/apps/web/src/components/NavigationTabs/index.tsx b/apps/web/src/components/NavigationTabs/index.tsx index 6b0575daa3a..91578d08135 100644 --- a/apps/web/src/components/NavigationTabs/index.tsx +++ b/apps/web/src/components/NavigationTabs/index.tsx @@ -3,7 +3,7 @@ import SettingsTab from 'components/Settings' import { Trans } from 'i18n' import { ReactNode } from 'react' import { ArrowLeft } from 'react-feather' -import { Link, useNavigate } from 'react-router-dom' +import { Link, useLocation } from 'react-router-dom' import { Box } from 'rebass' import { useAppDispatch } from 'state/hooks' import { resetMintState } from 'state/mint/actions' @@ -11,8 +11,8 @@ import { resetMintState as resetMintV3State } from 'state/mint/v3/actions' import styled, { useTheme } from 'styled-components' import { ThemedText } from 'theme/components' import { flexRowNoWrap } from 'theme/styles' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import { RowBetween } from '../Row' const Tabs = styled.div` @@ -51,7 +51,7 @@ export function FindPoolTabs({ origin }: { origin: string }) { - Import V2 pool + @@ -68,29 +68,37 @@ export function AddRemoveTabs({ adding, creating, autoSlippage, + positionID, children, }: { adding: boolean creating: boolean autoSlippage: Percent + positionID?: string showBackLink?: boolean children?: ReactNode }) { - const chainId = useChainId() + const { chainId } = useAccount() const theme = useTheme() // reset states on back const dispatch = useAppDispatch() - const navigate = useNavigate() + const { state } = useLocation() + const location = useLocation() + + // detect if back should redirect to v3 or v2 pool page + const poolLink = location.pathname.includes('add/v2') + ? '/pools/v2' + : '/pools' + (positionID ? `/${positionID.toString()}` : '') + + // If the 'from' state is set by the previous page route back to the previous page, if not, route back to base pool + const target = state?.from ?? poolLink return ( { - e.preventDefault() - navigate(-1) - + to={target} + onClick={() => { if (adding) { // not 100% sure both of these are needed dispatch(resetMintState()) @@ -103,11 +111,11 @@ export function AddRemoveTabs({ {creating ? ( - Create a pair + ) : adding ? ( - Add liquidity + ) : ( - Remove liquidity + )} {children && {children}} diff --git a/apps/web/src/components/NetworkAlert/NetworkAlert.tsx b/apps/web/src/components/NetworkAlert/NetworkAlert.tsx index f933526ab42..d5fbce118bb 100644 --- a/apps/web/src/components/NetworkAlert/NetworkAlert.tsx +++ b/apps/web/src/components/NetworkAlert/NetworkAlert.tsx @@ -1,13 +1,13 @@ import { getChainUI } from 'components/Logo/ChainLogo' import { RowBetween } from 'components/Row' -import { getChainInfo, useIsSupportedChainId } from 'constants/chains' +import { NetworkLayer, getChain, useIsSupportedChainId } from 'constants/chains' import { Trans } from 'i18n' import { ArrowUpRight } from 'react-feather' import styled from 'styled-components' import { ExternalLink, HideSmall, ThemedText } from 'theme/components' import { useIsDarkMode } from 'theme/components/ThemeToggle' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import Column from '../Column' const BridgeLink = styled(ExternalLink)<{ bgColor: string }>` @@ -45,26 +45,28 @@ const SubtitleText = styled(ThemedText.BodySmall)<{ $color: string }>` ` export function NetworkAlert() { - const chainId = useChainId() + const { chainId } = useAccount() const isSupportedChain = useIsSupportedChainId(chainId) const darkMode = useIsDarkMode() - if (!isSupportedChain) return null + if (!isSupportedChain) { + return null + } const { Symbol: ChainSymbol, bgColor, textColor } = getChainUI(chainId, darkMode) - const { label, bridge } = getChainInfo({ chainId }) + const chainInfo = getChain({ chainId }) - return bridge ? ( - + return chainInfo.networkLayer == NetworkLayer.L2 ? ( + - {{ label }} token bridge + - Deposit tokens to the {{ label }} network. + diff --git a/apps/web/src/components/NumericalInput/index.tsx b/apps/web/src/components/NumericalInput/index.tsx index 7e128d2b10e..ed00998010f 100644 --- a/apps/web/src/components/NumericalInput/index.tsx +++ b/apps/web/src/components/NumericalInput/index.tsx @@ -60,14 +60,18 @@ interface InputProps extends Omit, 'ref' | 'on maxDecimals?: number } +export function isInputGreaterThanDecimals(value: string, maxDecimals?: number): boolean { + const decimalGroups = value.split('.') + return !!maxDecimals && decimalGroups.length > 1 && decimalGroups[1].length > maxDecimals +} + const Input = forwardRef( ({ value, onUserInput, placeholder, prependSymbol, maxDecimals, ...rest }: InputProps, ref) => { const { formatterLocale } = useFormatterLocales() const enforcer = (nextUserInput: string) => { if (nextUserInput === '' || inputRegex.test(escapeRegExp(nextUserInput))) { - const decimalGroups = nextUserInput.split('.') - if (maxDecimals && decimalGroups.length > 1 && decimalGroups[1].length > maxDecimals) { + if (isInputGreaterThanDecimals(nextUserInput, maxDecimals)) { return } diff --git a/apps/web/src/components/Polling/ChainConnectivityWarning.tsx b/apps/web/src/components/Polling/ChainConnectivityWarning.tsx index 97b90986e47..e9f75a6031e 100644 --- a/apps/web/src/components/Polling/ChainConnectivityWarning.tsx +++ b/apps/web/src/components/Polling/ChainConnectivityWarning.tsx @@ -1,11 +1,11 @@ import { ChainId } from '@uniswap/sdk-core' -import { L2ChainInfo, getChainInfo, useSupportedChainId } from 'constants/chains' +import { getChain, useSupportedChainId } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import { Trans } from 'i18n' import { AlertTriangle } from 'react-feather' import styled from 'styled-components' import { MEDIA_WIDTHS } from 'theme' import { ExternalLink } from 'theme/components' -import { useChainId } from 'wagmi' const BodyRow = styled.div` color: ${({ theme }) => theme.neutral1}; @@ -51,9 +51,9 @@ const Wrapper = styled.div` ` export function ChainConnectivityWarning() { - const chainId = useChainId() + const { chainId } = useAccount() const supportedChain = useSupportedChainId(chainId) - const info = getChainInfo({ chainId: supportedChain, withFallback: true }) + const info = getChain({ chainId: supportedChain, withFallback: true }) const label = info.label return ( @@ -61,19 +61,19 @@ export function ChainConnectivityWarning() { - Network warning + {chainId === ChainId.MAINNET ? ( - You may have lost your network connection. + ) : ( - {{ label }} might be down right now, or you may have lost your network connection. + )}{' '} - {(info as L2ChainInfo).statusPage !== undefined && ( + {info.statusPage !== undefined && ( - Check network status{' '} - + {' '} + here. diff --git a/apps/web/src/components/Polling/index.tsx b/apps/web/src/components/Polling/index.tsx index f5f9da3e837..0ed9feb707c 100644 --- a/apps/web/src/components/Polling/index.tsx +++ b/apps/web/src/components/Polling/index.tsx @@ -12,8 +12,8 @@ import styled, { keyframes } from 'styled-components' import { ExternalLink } from 'theme/components' import { Text } from 'ui/src' import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import { MouseoverTooltip } from '../Tooltip' import { ChainConnectivityWarning } from './ChainConnectivityWarning' @@ -113,7 +113,7 @@ const Spinner = styled.div<{ warning: boolean }>` ` export default function Polling() { - const chainId = useChainId() + const { chainId } = useAccount() const isSupportedChain = useIsSupportedChainId(chainId) const blockNumber = useBlockNumber() const [isMounting, setIsMounting] = useState(false) @@ -158,7 +158,9 @@ export default function Polling() { //TODO - chainlink gas oracle is really slow. Can we get a better data source? const blockExternalLinkHref = useMemo(() => { - if (!chainId || !blockNumber) return '' + if (!chainId || !blockNumber) { + return '' + } return getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) }, [blockNumber, chainId]) @@ -171,11 +173,7 @@ export default function Polling() { setIsHover(true)} onMouseLeave={() => setIsHover(false)}> - The most recent block number on this network. Prices update on every block.} - > - {blockNumber}  - + }>{blockNumber}  {isMounting && }{' '} diff --git a/apps/web/src/components/Pools/PoolDetails/ChartSection/index.tsx b/apps/web/src/components/Pools/PoolDetails/ChartSection/index.tsx index ea9e8f82f2e..a8a04c49085 100644 --- a/apps/web/src/components/Pools/PoolDetails/ChartSection/index.tsx +++ b/apps/web/src/components/Pools/PoolDetails/ChartSection/index.tsx @@ -54,15 +54,18 @@ const StyledChart: typeof Chart = styled(Chart)` const PDPChartTypeSelector = ({ chartType, onChartTypeChange, + disabledOption, }: { chartType: PoolsDetailsChartType onChartTypeChange: (c: PoolsDetailsChartType) => void + disabledOption?: PoolsDetailsChartType }) => ( ) @@ -171,7 +174,7 @@ export default function ChartSection(props: ChartSectionProps) { return } if (activeQuery.dataQuality === DataQuality.INVALID || !currencyA || !currencyB) { - const errorText = loading ? undefined : Unable to display historical data for the current pool. + const errorText = loading ? undefined : return } @@ -188,16 +191,25 @@ export default function ChartSection(props: ChartSectionProps) { // BE does not support hourly price data for pools const filteredTimeOptions = useMemo(() => { if (activeQuery.chartType === ChartType.PRICE) { + if (timePeriod === TimePeriod.HOUR) { + setTimePeriod(TimePeriod.DAY) + } return DEFAULT_PILL_TIME_SELECTOR_OPTIONS.filter((option) => option.value !== TimePeriodDisplay.HOUR) } return DEFAULT_PILL_TIME_SELECTOR_OPTIONS - }, [activeQuery.chartType]) + }, [activeQuery.chartType, setTimePeriod, timePeriod]) + + const disabledChartOption = props.poolData?.protocolVersion === ProtocolVersion.V2 ? ChartType.LIQUIDITY : undefined return (
{ChartBody} - + {activeQuery.chartType !== ChartType.LIQUIDITY && ( = currentTick @@ -349,8 +363,8 @@ function LiquidityChart({ isReversed: boolean chainId: ChainId }) { - const tokenADescriptor = tokenA.symbol ?? tokenA.name ?? t`Token A` - const tokenBDescriptor = tokenB.symbol ?? tokenB.name ?? t`Token B` + const tokenADescriptor = tokenA.symbol ?? tokenA.name ?? t('common.tokenA') + const tokenBDescriptor = tokenB.symbol ?? tokenB.name ?? t('common.tokenB') const { tickData, activeTick, loading } = useLiquidityBarData({ tokenA, @@ -372,7 +386,9 @@ function LiquidityChart({ } }, [activeTick, isReversed, theme, tickData]) - if (loading) return + if (loading) { + return + } return ( {`1 ${tokenBDescriptor} = ${displayPoint?.price1} ${tokenADescriptor}`} {displayPoint && displayPoint.tick === activeTick && ( - Active tick range + )}
diff --git a/apps/web/src/components/Pools/PoolDetails/PoolDetailsHeader.tsx b/apps/web/src/components/Pools/PoolDetails/PoolDetailsHeader.tsx index 303fea269de..ef8375fa41f 100644 --- a/apps/web/src/components/Pools/PoolDetails/PoolDetailsHeader.tsx +++ b/apps/web/src/components/Pools/PoolDetails/PoolDetailsHeader.tsx @@ -74,10 +74,10 @@ export function PoolDetailsBreadcrumb({ chainId, poolAddress, token0, token1, lo return ( - Explore + - Pools + {loading || !poolAddress ? ( @@ -204,7 +204,9 @@ const ContractsDropdownRow = ({ ) : ( )} - {isPool ? Pool : tokens[0]?.symbol} + + {isPool ? : tokens[0]?.symbol} + {shortenAddress(address)} @@ -259,7 +261,7 @@ const PoolDetailsHeaderActions = ({ } - tooltipText={t`Explorers`} + tooltipText={t('pool.explorers')} hideChevron buttonCss={ActionButtonStyle} menuFlyoutCss={ContractsModalContainer} diff --git a/apps/web/src/components/Pools/PoolDetails/PoolDetailsLink.tsx b/apps/web/src/components/Pools/PoolDetails/PoolDetailsLink.tsx index 692ab3882e7..69d92bec0f0 100644 --- a/apps/web/src/components/Pools/PoolDetails/PoolDetailsLink.tsx +++ b/apps/web/src/components/Pools/PoolDetails/PoolDetailsLink.tsx @@ -155,7 +155,7 @@ export function PoolDetailsLink({ address, chainId, tokens, loading }: PoolDetai ) : ( )} - {isPool ? Pool : tokens[0]?.name} + {isPool ? : tokens[0]?.name} {isPool ? ( `${tokens[0]?.symbol} / ${tokens[1]?.symbol}` @@ -168,7 +168,7 @@ export function PoolDetailsLink({ address, chainId, tokens, loading }: PoolDetai {!isNative && ( - + {shortenAddress(address, truncateAddress ? 2 : undefined, truncateAddress === 'both' ? 2 : undefined)} diff --git a/apps/web/src/components/Pools/PoolDetails/PoolDetailsPositionsTable.tsx b/apps/web/src/components/Pools/PoolDetails/PoolDetailsPositionsTable.tsx index c4d73a935aa..a38fd27c3e4 100644 --- a/apps/web/src/components/Pools/PoolDetails/PoolDetailsPositionsTable.tsx +++ b/apps/web/src/components/Pools/PoolDetails/PoolDetailsPositionsTable.tsx @@ -96,7 +96,9 @@ function PositionRow({ positionInfo }: { positionInfo: PositionInfo }) { const { formatTickPrice } = useFormatter() const onClick = useCallback(async () => { - if (walletChainId !== positionInfo.chainId) await switchChain(positionInfo.chainId) + if (walletChainId !== positionInfo.chainId) { + await switchChain(positionInfo.chainId) + } navigate('/pool/' + positionInfo.details.tokenId) }, [navigate, positionInfo.chainId, positionInfo.details.tokenId, switchChain, walletChainId]) @@ -131,7 +133,8 @@ function PositionRow({ positionInfo }: { positionInfo: PositionInfo }) { - Min:  + +   {formatTickPrice({ price: priceLower, atLimit: ticksAtLimit, @@ -139,12 +142,14 @@ function PositionRow({ positionInfo }: { positionInfo: PositionInfo }) { })}   {positionInfo.pool.token0.symbol}  - per  + +   {positionInfo.pool.token1.symbol} - Max:  + +   {formatTickPrice({ price: priceUpper, atLimit: ticksAtLimit, @@ -152,7 +157,8 @@ function PositionRow({ positionInfo }: { positionInfo: PositionInfo }) { })}   {positionInfo.pool.token0.symbol}  - per  + +   {positionInfo.pool.token1.symbol} diff --git a/apps/web/src/components/Pools/PoolDetails/PoolDetailsStats.test.tsx b/apps/web/src/components/Pools/PoolDetails/PoolDetailsStats.test.tsx index de9d0b915ce..16cddcdd3bb 100644 --- a/apps/web/src/components/Pools/PoolDetails/PoolDetailsStats.test.tsx +++ b/apps/web/src/components/Pools/PoolDetails/PoolDetailsStats.test.tsx @@ -1,11 +1,11 @@ -import 'test-utils/tokens/mocks' - import { enableNetConnect } from 'nock' import store from 'state' import { addSerializedToken } from 'state/user/reducer' import { validPoolDataResponse } from 'test-utils/pools/fixtures' import { act, render, screen } from 'test-utils/render' +import 'test-utils/tokens/mocks' import { BREAKPOINTS } from 'theme' + import { PoolDetailsStats } from './PoolDetailsStats' describe('PoolDetailsStats', () => { diff --git a/apps/web/src/components/Pools/PoolDetails/PoolDetailsStats.tsx b/apps/web/src/components/Pools/PoolDetails/PoolDetailsStats.tsx index 32e18badaad..1ad0363ece3 100644 --- a/apps/web/src/components/Pools/PoolDetails/PoolDetailsStats.tsx +++ b/apps/web/src/components/Pools/PoolDetails/PoolDetailsStats.tsx @@ -212,11 +212,11 @@ export function PoolDetailsStats({ poolData, isReversed, chainId, loading }: Poo return ( - Stats + - Pool balances + @@ -230,13 +230,24 @@ export function PoolDetailsStats({ poolData, isReversed, chainId, loading }: Poo )} {poolData?.tvlUSD && ( - TVL
} value={poolData.tvlUSD} delta={poolData.tvlUSDChange} /> + } + value={poolData.tvlUSD} + delta={poolData.tvlUSDChange} + /> )} {poolData?.volumeUSD24H !== undefined && ( - 24H volume
} value={poolData.volumeUSD24H} delta={poolData.volumeUSD24HChange} /> + } + value={poolData.volumeUSD24H} + delta={poolData.volumeUSD24HChange} + /> )} {poolData?.volumeUSD24H !== undefined && poolData?.feeTier !== undefined && ( - 24H fees
} value={poolData.volumeUSD24H * (poolData.feeTier / 1000000)} /> + } + value={poolData.volumeUSD24H * (poolData.feeTier / 1000000)} + /> )} ) diff --git a/apps/web/src/components/Pools/PoolDetails/PoolDetailsStatsButtons.test.tsx b/apps/web/src/components/Pools/PoolDetails/PoolDetailsStatsButtons.test.tsx index 929cf70aef5..3a9bdf26f1a 100644 --- a/apps/web/src/components/Pools/PoolDetails/PoolDetailsStatsButtons.test.tsx +++ b/apps/web/src/components/Pools/PoolDetails/PoolDetailsStatsButtons.test.tsx @@ -1,12 +1,12 @@ -import 'test-utils/tokens/mocks' - import userEvent from '@testing-library/user-event' +import { ChainId } from '@uniswap/sdk-core' import useMultiChainPositions from 'components/AccountDrawer/MiniPortfolio/Pools/useMultiChainPositions' import store from 'state' import { addSerializedToken } from 'state/user/reducer' import { mocked } from 'test-utils/mocked' import { useMultiChainPositionsReturnValue, validBEPoolToken0, validBEPoolToken1 } from 'test-utils/pools/fixtures' import { act, render, screen } from 'test-utils/render' +import 'test-utils/tokens/mocks' import { PoolDetailsStatsButtons } from './PoolDetailsStatsButtons' @@ -14,11 +14,11 @@ jest.mock('components/AccountDrawer/MiniPortfolio/Pools/useMultiChainPositions') describe('PoolDetailsStatsButton', () => { const mockProps = { - chainId: 1, + chainId: ChainId.MAINNET, token0: validBEPoolToken0, token1: validBEPoolToken1, feeTier: 500, - } + } as const const mockPropsTokensReversed = { ...mockProps, diff --git a/apps/web/src/components/Pools/PoolDetails/PoolDetailsStatsButtons.tsx b/apps/web/src/components/Pools/PoolDetails/PoolDetailsStatsButtons.tsx index 1ab2bfc82fa..3beed322fda 100644 --- a/apps/web/src/components/Pools/PoolDetails/PoolDetailsStatsButtons.tsx +++ b/apps/web/src/components/Pools/PoolDetails/PoolDetailsStatsButtons.tsx @@ -1,4 +1,3 @@ -import { useWeb3React } from '@web3-react/core' import { Scrim } from 'components/AccountDrawer' import { PositionInfo } from 'components/AccountDrawer/MiniPortfolio/Pools/cache' import useMultiChainPositions from 'components/AccountDrawer/MiniPortfolio/Pools/useMultiChainPositions' @@ -14,12 +13,13 @@ import { getPriorityWarning, StrongWarning, useTokenWarning } from 'constants/to import { useTokenBalancesQuery } from 'graphql/data/apollo/TokenBalancesProvider' import { gqlToCurrency } from 'graphql/data/util' import { useScreenSize } from 'hooks/screenSize' +import { useAccount } from 'hooks/useAccount' import { useSwitchChain } from 'hooks/useSwitchChain' import { Trans } from 'i18n' import { Swap } from 'pages/Swap' import { useMemo, useReducer } from 'react' import { Plus, X } from 'react-feather' -import { useNavigate } from 'react-router-dom' +import { useLocation, useNavigate } from 'react-router-dom' import styled from 'styled-components' import { BREAKPOINTS } from 'theme' import { ClickableStyle, ThemedText } from 'theme/components' @@ -153,12 +153,13 @@ function findMatchingPosition(positions: PositionInfo[], token0?: Token, token1? } export function PoolDetailsStatsButtons({ chainId, token0, token1, feeTier, loading }: PoolDetailsStatsButtonsProps) { - const { chainId: walletChainId, account } = useWeb3React() - const { positions: userOwnedPositions } = useMultiChainPositions(account ?? '', chainId ? [chainId] : undefined) + const { chainId: walletChainId, address } = useAccount() + const { positions: userOwnedPositions } = useMultiChainPositions(address ?? '', chainId ? [chainId] : undefined) const position = userOwnedPositions && findMatchingPosition(userOwnedPositions, token0, token1, feeTier) const tokenId = position?.details.tokenId const switchChain = useSwitchChain() const navigate = useNavigate() + const location = useLocation() const currency0 = token0 && gqlToCurrency(token0) const currency1 = token1 && gqlToCurrency(token1) @@ -194,8 +195,12 @@ export function PoolDetailsStatsButtons({ chainId, token0, token1, feeTier, load const handleAddLiquidity = async () => { if (currency0 && currency1) { - if (walletChainId !== chainId && chainId) await switchChain(chainId) - navigate(`/add/${currencyId(currency0)}/${currencyId(currency1)}/${feeTier}${tokenId ? `/${tokenId}` : ''}`) + if (walletChainId !== chainId && chainId) { + await switchChain(chainId) + } + navigate(`/add/${currencyId(currency0)}/${currencyId(currency1)}/${feeTier}${tokenId ? `/${tokenId}` : ''}`, { + state: { from: location.pathname }, + }) } } const [swapModalOpen, toggleSwapModalOpen] = useReducer((state) => !state, false) @@ -206,7 +211,7 @@ export function PoolDetailsStatsButtons({ chainId, token0, token1, feeTier, load const token1Warning = useTokenWarning(token1?.address, chainId) const priorityWarning = getPriorityWarning(token0Warning, token1Warning) - if (loading || !currency0 || !currency1) + if (loading || !currency0 || !currency1) { return ( @@ -216,14 +221,15 @@ export function PoolDetailsStatsButtons({ chainId, token0, token1, feeTier, load ) + } return ( - {account && ( + {address && ( - Your balances + @@ -240,21 +246,21 @@ export function PoolDetailsStatsButtons({ chainId, token0, token1, feeTier, load {swapModalOpen ? ( <> {screenSizeLargerThanTablet && } - Close + ) : ( <> {screenSizeLargerThanTablet && } - Swap + )} @@ -262,12 +268,12 @@ export function PoolDetailsStatsButtons({ chainId, token0, token1, feeTier, load {screenSizeLargerThanTablet && } - Add liquidity + diff --git a/apps/web/src/components/Pools/PoolDetails/PoolDetailsTable.tsx b/apps/web/src/components/Pools/PoolDetails/PoolDetailsTable.tsx index c402520b206..ee5d5f869be 100644 --- a/apps/web/src/components/Pools/PoolDetails/PoolDetailsTable.tsx +++ b/apps/web/src/components/Pools/PoolDetails/PoolDetailsTable.tsx @@ -57,14 +57,14 @@ export function PoolDetailsTableTab({ onClick={() => setActiveTable(PoolDetailsTableTabs.TRANSACTIONS)} disabled={!positionsInThisPool.length} > - Transactions + {Boolean(positionsInThisPool.length) && ( setActiveTable(PoolDetailsTableTabs.POSITIONS)} > - Positions + {` (${positionsInThisPool?.length})`} )} diff --git a/apps/web/src/components/Pools/PoolDetails/PoolDetailsTransactionsTable.tsx b/apps/web/src/components/Pools/PoolDetails/PoolDetailsTransactionsTable.tsx index 0a2c5d851e1..6bd391f4dbe 100644 --- a/apps/web/src/components/Pools/PoolDetails/PoolDetailsTransactionsTable.tsx +++ b/apps/web/src/components/Pools/PoolDetails/PoolDetailsTransactionsTable.tsx @@ -108,7 +108,7 @@ export function PoolDetailsTransactionsTable({ {sortState.sortBy === Transaction_OrderBy.Timestamp && } - Time + @@ -133,19 +133,26 @@ export function PoolDetailsTransactionsTable({ color = 'success' text = ( - Buy {token0?.symbol} + +  {token0?.symbol} ) } else if (row.type === PoolTableTransactionType.SELL) { color = 'critical' text = ( - Sell {token0?.symbol} + +  {token0?.symbol} ) } else { color = row.type === PoolTableTransactionType.MINT ? 'success' : 'critical' - text = row.type === PoolTableTransactionType.MINT ? Add : Remove + text = + row.type === PoolTableTransactionType.MINT ? ( + + ) : ( + + ) } return {text} }, @@ -162,7 +169,7 @@ export function PoolDetailsTransactionsTable({ toggleFilterModal={toggleFilterModal} /> - Type + @@ -255,7 +262,7 @@ export function PoolDetailsTransactionsTable({ grow > - Wallet + ), diff --git a/apps/web/src/components/Pools/PoolDetails/__snapshots__/PoolDetailsStatsButtons.test.tsx.snap b/apps/web/src/components/Pools/PoolDetails/__snapshots__/PoolDetailsStatsButtons.test.tsx.snap index 4f32b1d561c..808adda4df5 100644 --- a/apps/web/src/components/Pools/PoolDetails/__snapshots__/PoolDetailsStatsButtons.test.tsx.snap +++ b/apps/web/src/components/Pools/PoolDetails/__snapshots__/PoolDetailsStatsButtons.test.tsx.snap @@ -1366,8 +1366,15 @@ exports[`PoolDetailsStatsButton renders both buttons correctly 1`] = `
diff --git a/apps/web/src/components/Pools/PoolDetails/__snapshots__/PoolDetailsTransactionTable.test.tsx.snap b/apps/web/src/components/Pools/PoolDetails/__snapshots__/PoolDetailsTransactionTable.test.tsx.snap index c33bcb1ebfe..8715c4d5a35 100644 --- a/apps/web/src/components/Pools/PoolDetails/__snapshots__/PoolDetailsTransactionTable.test.tsx.snap +++ b/apps/web/src/components/Pools/PoolDetails/__snapshots__/PoolDetailsTransactionTable.test.tsx.snap @@ -1889,7 +1889,7 @@ exports[`PoolDetailsTransactionsTable renders error state 1`] = `
- Data is unavailable at the moment; we're working on a fix + Data is unavailable at the moment; we’re working on a fix
diff --git a/apps/web/src/components/Pools/PoolTable/PoolTable.tsx b/apps/web/src/components/Pools/PoolTable/PoolTable.tsx index 54a9270c8f9..3f85fbdd7aa 100644 --- a/apps/web/src/components/Pools/PoolTable/PoolTable.tsx +++ b/apps/web/src/components/Pools/PoolTable/PoolTable.tsx @@ -30,12 +30,7 @@ const HEADER_DESCRIPTIONS: Record = { [PoolSortFields.Volume24h]: undefined, [PoolSortFields.VolumeWeek]: undefined, [PoolSortFields.TxCount]: undefined, - [PoolSortFields.OneDayApr]: ( - - 1 day APR refers to the amount of trading fees relative to total value locked (TVL) within a pool. 1 day APR = 24H - Fees / TVL - - ), + [PoolSortFields.OneDayApr]: , } const TableWrapper = styled.div` @@ -116,11 +111,11 @@ function useSetSortMethod(newSortMethod: PoolSortFields) { } const HEADER_TEXT: Record = { - [PoolSortFields.TVL]: TVL, - [PoolSortFields.Volume24h]: 1 day volume, - [PoolSortFields.VolumeWeek]: 7 day volume, - [PoolSortFields.OneDayApr]: 1 day APR, - [PoolSortFields.TxCount]: Transactions, + [PoolSortFields.TVL]: , + [PoolSortFields.Volume24h]: , + [PoolSortFields.VolumeWeek]: , + [PoolSortFields.OneDayApr]: , + [PoolSortFields.TxCount]: , } function PoolTableHeader({ @@ -271,7 +266,7 @@ export function PoolsTable({ header: () => ( - Pool + ), diff --git a/apps/web/src/components/Pools/PoolTable/__snapshots__/PoolTable.test.tsx.snap b/apps/web/src/components/Pools/PoolTable/__snapshots__/PoolTable.test.tsx.snap index 5ecc3b57da3..47619dea69b 100644 --- a/apps/web/src/components/Pools/PoolTable/__snapshots__/PoolTable.test.tsx.snap +++ b/apps/web/src/components/Pools/PoolTable/__snapshots__/PoolTable.test.tsx.snap @@ -59,6 +59,22 @@ exports[`PoolTable renders data filled state 1`] = ` letter-spacing: -0.01em; } +.c30 { + height: 16px; + width: 16px; +} + +.c30 path { + stroke: #FC72FF; + background: #7D7D7D; + fill: none; +} + +.c31 { + -webkit-animation: 2s fvtopB linear infinite; + animation: 2s fvtopB linear infinite; +} + .c23 { display: -webkit-box; display: -webkit-flex; @@ -98,22 +114,6 @@ exports[`PoolTable renders data filled state 1`] = ` left: 0; } -.c30 { - height: 16px; - width: 16px; -} - -.c30 path { - stroke: #FC72FF; - background: #7D7D7D; - fill: none; -} - -.c31 { - -webkit-animation: 2s fvtopB linear infinite; - animation: 2s fvtopB linear infinite; -} - .c1 { display: -webkit-box; display: -webkit-flex; @@ -2029,7 +2029,7 @@ exports[`PoolTable renders error state 1`] = `
- Data is unavailable at the moment; we're working on a fix + Data is unavailable at the moment; we’re working on a fix
diff --git a/apps/web/src/components/Popups/ClaimPopup.tsx b/apps/web/src/components/Popups/ClaimPopup.tsx index bc22525afb0..fa0f4d8814c 100644 --- a/apps/web/src/components/Popups/ClaimPopup.tsx +++ b/apps/web/src/components/Popups/ClaimPopup.tsx @@ -100,20 +100,23 @@ export default function ClaimPopup() { 🎉 {' '} - UNI has arrived{' '} + {' '} 🎉 - - Thanks for being part of the Uniswap community - + , + }} + /> - Claim your UNI tokens + diff --git a/apps/web/src/components/Popups/PopupContent.tsx b/apps/web/src/components/Popups/PopupContent.tsx index 0b33d67a89a..df212bbedbe 100644 --- a/apps/web/src/components/Popups/PopupContent.tsx +++ b/apps/web/src/components/Popups/PopupContent.tsx @@ -83,11 +83,11 @@ export function FailedNetworkSwitchPopup({ chainId, onClose }: { chainId: ChainI - Failed to switch networks + - To use Uniswap on {{ label: chainInfo.label }}, switch the network in your wallet’s settings. + @@ -148,7 +148,9 @@ export function TransactionPopupContent({ const { formatNumber } = useFormatter() const { data: activity } = useQuery(getTransactionToActivityQueryOptions(transaction, chainId, formatNumber)) - if (!transaction || !activity) return null + if (!transaction || !activity) { + return null + } const onClick = () => window.open(getExplorerLink(activity.chainId, activity.hash, ExplorerDataType.TRANSACTION), '_blank') @@ -163,7 +165,9 @@ export function UniswapXOrderPopupContent({ orderHash, onClose }: { orderHash: s const { formatNumber } = useFormatter() const { data: activity } = useQuery(getSignatureToActivityQueryOptions(order, formatNumber)) - if (!activity || !order) return null + if (!activity || !order) { + return null + } const onClick = () => openOffchainActivityModal(order, { inputLogo: activity?.logos?.[0], outputLogo: activity?.logos?.[1] }) diff --git a/apps/web/src/components/Popups/PopupItem.tsx b/apps/web/src/components/Popups/PopupItem.tsx index c78b3b5c1d2..509d336df9b 100644 --- a/apps/web/src/components/Popups/PopupItem.tsx +++ b/apps/web/src/components/Popups/PopupItem.tsx @@ -1,6 +1,6 @@ import { useSupportedChainId } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import { useEffect } from 'react' -import { useChainId } from 'wagmi' import { useRemovePopup } from '../../state/application/hooks' import { PopupContent, PopupType } from '../../state/application/reducer' @@ -19,7 +19,9 @@ export default function PopupItem({ const onClose = () => removePopup(popKey) useEffect(() => { - if (removeAfterMs === null) return undefined + if (removeAfterMs === null) { + return undefined + } const timeout = setTimeout(() => { removePopup(popKey) @@ -30,7 +32,7 @@ export default function PopupItem({ } }, [popKey, removeAfterMs, removePopup]) - const chainId = useChainId() + const { chainId } = useAccount() const supportedChainId = useSupportedChainId(chainId) switch (content.type) { diff --git a/apps/web/src/components/Popups/UniconV2InfoPopup.tsx b/apps/web/src/components/Popups/UniconV2InfoPopup.tsx index b70868c2b85..311d3254b4f 100644 --- a/apps/web/src/components/Popups/UniconV2InfoPopup.tsx +++ b/apps/web/src/components/Popups/UniconV2InfoPopup.tsx @@ -2,13 +2,13 @@ import Column from 'components/Column' import Identicon, { IdenticonType, useIdenticonType } from 'components/Identicon' import { PopupContainer } from 'components/Popups/PopupContent' import Row from 'components/Row' +import { useAccount } from 'hooks/useAccount' import { Trans } from 'i18n' import { useAtom } from 'jotai' import { atomWithStorage } from 'jotai/utils' import { X } from 'react-feather' import styled from 'styled-components' import { ClickableStyle, ThemedText } from 'theme/components' -import { useAccount } from 'wagmi' const StyledColumn = styled(Column)` width: 242px; diff --git a/apps/web/src/components/PositionCard/Sushi.tsx b/apps/web/src/components/PositionCard/Sushi.tsx index 1c109c16fff..05902f611ae 100644 --- a/apps/web/src/components/PositionCard/Sushi.tsx +++ b/apps/web/src/components/PositionCard/Sushi.tsx @@ -48,7 +48,7 @@ export default function SushiPositionCard({ tokenA, tokenB, liquidityToken, bord {!currency0 || !currency1 ? ( - Loading + ) : ( `${currency0.symbol}/${currency1.symbol}` @@ -65,7 +65,7 @@ export default function SushiPositionCard({ tokenA, tokenB, liquidityToken, bord as={Link} to={`/migrate/v2/${liquidityToken.address}`} > - Migrate + diff --git a/apps/web/src/components/PositionCard/V2.tsx b/apps/web/src/components/PositionCard/V2.tsx index 14253ae89a2..8e2c117d819 100644 --- a/apps/web/src/components/PositionCard/V2.tsx +++ b/apps/web/src/components/PositionCard/V2.tsx @@ -86,10 +86,10 @@ export default function V2PositionCard({ pair, border, stakedBalance }: Position {!currency0 || !currency1 ? ( - Loading + ) : ( - `${{ sym0: currency0.symbol }}/${{ sym1: currency1.symbol }}` + `${currency0.symbol}/${currency1.symbol}` )} @@ -102,12 +102,12 @@ export default function V2PositionCard({ pair, border, stakedBalance }: Position > {showMore ? ( <> - Manage + ) : ( <> - Manage + )} @@ -119,7 +119,7 @@ export default function V2PositionCard({ pair, border, stakedBalance }: Position - Your total pool tokens: + {userPoolBalance ? userPoolBalance.toSignificant(4) : '-'} @@ -128,7 +128,7 @@ export default function V2PositionCard({ pair, border, stakedBalance }: Position {stakedBalance && ( - Pool tokens in rewards pool: + {stakedBalance.toSignificant(4)} @@ -138,7 +138,7 @@ export default function V2PositionCard({ pair, border, stakedBalance }: Position - Pooled {{ sym: currency0.symbol }}: + {token0Deposited ? ( @@ -156,7 +156,7 @@ export default function V2PositionCard({ pair, border, stakedBalance }: Position - Pooled {{ sym: currency1.symbol }}: + {token1Deposited ? ( @@ -173,7 +173,7 @@ export default function V2PositionCard({ pair, border, stakedBalance }: Position - Your pool share: + {poolTokenPercentage @@ -191,7 +191,7 @@ export default function V2PositionCard({ pair, border, stakedBalance }: Position to={`/migrate/v2/${pair.liquidityToken.address}`} width="64%" > - Migrate + - Remove + )} diff --git a/apps/web/src/components/PositionCard/index.tsx b/apps/web/src/components/PositionCard/index.tsx index a6686da4796..743daae755d 100644 --- a/apps/web/src/components/PositionCard/index.tsx +++ b/apps/web/src/components/PositionCard/index.tsx @@ -83,7 +83,7 @@ export function MinimalPositionCard({ pair, showUnwrapped = false, border }: Pos - Your position + @@ -103,7 +103,7 @@ export function MinimalPositionCard({ pair, showUnwrapped = false, border }: Pos - Your pool share: + {poolTokenPercentage ? poolTokenPercentage.toFixed(6) + '%' : '-'} @@ -146,10 +146,7 @@ export function MinimalPositionCard({ pair, showUnwrapped = false, border }: Pos ⭐️ {' '} - - By adding liquidity you'll earn 0.3% of all trades on this pair proportional to your share of the - pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity. - {' '} + {' '} )} @@ -202,7 +199,7 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi {!currency0 || !currency1 ? ( - Loading + ) : ( `${currency0.symbol}/${currency1.symbol}` @@ -213,12 +210,12 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi setShowMore(!showMore)}> {showMore ? ( <> - Manage + ) : ( <> - Manage + )} @@ -230,7 +227,7 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi - Your total pool tokens: + {userPoolBalance ? userPoolBalance.toSignificant(4) : '-'} @@ -239,7 +236,7 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi {stakedBalance && ( - Pool tokens in rewards pool: + {stakedBalance.toSignificant(4)} @@ -249,7 +246,7 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi - Pooled {{ sym: currency0.symbol }}: + {token0Deposited ? ( @@ -267,7 +264,7 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi - Pooled {{ sym: currency1.symbol }}: + {token1Deposited ? ( @@ -284,13 +281,16 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi - Your pool share: + {poolTokenPercentage ? ( - - {{ amt: poolTokenPercentage.toFixed(2) === '0.00' ? '<0.01' : poolTokenPercentage.toFixed(2) }}% - + ) : ( '-' )} @@ -302,9 +302,8 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi style={{ width: '100%', textAlign: 'center' }} href={`https://v2.info.uniswap.org/account/${account}`} > - - View accrued fees and analytics - + + {userDefaultPoolBalance && JSBI.greaterThan(userDefaultPoolBalance.quotient, BIG_INT_ZERO) && ( @@ -316,7 +315,7 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi to={`/migrate/v2/${pair.liquidityToken.address}`} width="32%" > - Migrate + - Add + - Remove + )} @@ -346,7 +345,7 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi to={`/uni/${currencyId(currency0)}/${currencyId(currency1)}`} width="100%" > - Manage liquidity in rewards pool + )} diff --git a/apps/web/src/components/PositionList/index.tsx b/apps/web/src/components/PositionList/index.tsx index 10f2e939807..70e2fd416e4 100644 --- a/apps/web/src/components/PositionList/index.tsx +++ b/apps/web/src/components/PositionList/index.tsx @@ -74,7 +74,7 @@ export default function PositionList({ <>
- Your positions + {positions && ' (' + positions.length + ')'}
@@ -84,18 +84,18 @@ export default function PositionList({ setUserHideClosedPositions(!userHideClosedPositions) }} > - {userHideClosedPositions ? Show closed positions : Hide closed positions} + {userHideClosedPositions ? : }
- Your positions + { setUserHideClosedPositions(!userHideClosedPositions) }} > - {userHideClosedPositions ? Show closed positions : Hide closed positions} + {userHideClosedPositions ? : } diff --git a/apps/web/src/components/PositionListItem/PositionListItem.test.tsx b/apps/web/src/components/PositionListItem/PositionListItem.test.tsx index 0a6e6629f3f..6d984c75b75 100644 --- a/apps/web/src/components/PositionListItem/PositionListItem.test.tsx +++ b/apps/web/src/components/PositionListItem/PositionListItem.test.tsx @@ -16,7 +16,9 @@ jest.mock('utils/unwrappedToken') beforeEach(() => { mocked(useToken).mockImplementation((tokenAddress?: string) => { - if (!tokenAddress) return undefined + if (!tokenAddress) { + return undefined + } return new Token(1, tokenAddress, 6, 'symbol', 'name') }) mocked(usePool).mockReturnValue([ diff --git a/apps/web/src/components/PositionListItem/index.tsx b/apps/web/src/components/PositionListItem/index.tsx index 95b9dbd33a9..55acd8f9c59 100644 --- a/apps/web/src/components/PositionListItem/index.tsx +++ b/apps/web/src/components/PositionListItem/index.tsx @@ -225,7 +225,8 @@ export default function PositionListItem({ - Min: + +   {formatTickPrice({ @@ -234,9 +235,13 @@ export default function PositionListItem({ direction: Bound.LOWER, })}{' '} - - per - + , + y: , + }} + /> {' '} {' '} @@ -246,7 +251,7 @@ export default function PositionListItem({ - Max: + {formatTickPrice({ @@ -255,10 +260,13 @@ export default function PositionListItem({ direction: Bound.UPPER, })}{' '} - - per{' '} - - + , + y: , + }} + /> ) : ( diff --git a/apps/web/src/components/PositionPreview/index.tsx b/apps/web/src/components/PositionPreview/index.tsx index 82535c5369d..3786f5a3c1b 100644 --- a/apps/web/src/components/PositionPreview/index.tsx +++ b/apps/web/src/components/PositionPreview/index.tsx @@ -103,7 +103,7 @@ export const PositionPreview = ({ - Fee tier + {formatDelta(position?.pool?.fee / BIPS_BASE)} @@ -123,7 +123,7 @@ export const PositionPreview = ({ - Min price + {formatTickPrice({ @@ -133,12 +133,13 @@ export const PositionPreview = ({ })} - - {{ sym: quoteCurrency.symbol }} per {{ symB: baseCurrency.symbol }} - + - Your position will be 100% composed of {{ sym: baseCurrency?.symbol }} at this price + @@ -146,7 +147,7 @@ export const PositionPreview = ({ - Max price + {formatTickPrice({ @@ -156,12 +157,13 @@ export const PositionPreview = ({ })} - - {{ sym: quoteCurrency.symbol }} per {{ symB: baseCurrency.symbol }} - + - Your position will be 100% composed of {{ sym: quoteCurrency?.symbol }} at this price + @@ -169,16 +171,17 @@ export const PositionPreview = ({ - Current price + {`${formatPrice({ price, type: NumberType.TokenTx, })} `} - - {{ sym: quoteCurrency.symbol }} per {{ symB: baseCurrency.symbol }} - + diff --git a/apps/web/src/components/PrivacyPolicy/index.tsx b/apps/web/src/components/PrivacyPolicy/index.tsx index 26b131654cb..2a2f29f7ea9 100644 --- a/apps/web/src/components/PrivacyPolicy/index.tsx +++ b/apps/web/src/components/PrivacyPolicy/index.tsx @@ -1,5 +1,4 @@ import { SharedEventName } from '@uniswap/analytics-events' -import { sendAnalyticsEvent } from 'analytics' import Card, { DarkGrayCard } from 'components/Card' import Row, { AutoRow, RowBetween } from 'components/Row' import { Trans } from 'i18n' @@ -7,8 +6,9 @@ import { useEffect, useRef } from 'react' import { ArrowDown, Info, X } from 'react-feather' import styled from 'styled-components' import { ExternalLink, ThemedText } from 'theme/components' +import { ModalName } from 'uniswap/src/features/telemetry/constants' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { isMobile } from 'uniswap/src/utils/platform' - import { useModalIsOpen, useTogglePrivacyPolicy } from '../../state/application/hooks' import { ApplicationModal } from '../../state/application/reducer' import { AutoColumn } from '../Column' @@ -50,33 +50,30 @@ const StyledLinkOut = styled(ArrowDown)` const EXTERNAL_APIS = [ { name: 'Auto Router', - description: The app fetches the optimal trade route from a Uniswap Labs server., + description: , }, { name: 'Infura', - description: The app fetches on-chain data and constructs contract calls with an Infura API., + description: , }, { name: 'TRM Labs', description: ( <> - - The app securely collects your wallet address and shares it with TRM Labs Inc. for risk and compliance - reasons. - {' '} + {' '} - Learn more + ), }, { name: 'Google Analytics & Amplitude', - description: The app logs anonymized usage statistics in order to improve over time., + description: , }, { name: 'The Graph', - description: The app fetches blockchain data from The Graph’s hosted service., + description: , }, ] @@ -86,11 +83,12 @@ export function PrivacyPolicyModal() { const toggle = useTogglePrivacyPolicy() useEffect(() => { - if (!open) return + if (!open) { + return + } sendAnalyticsEvent(SharedEventName.PAGE_VIEWED, { - category: 'Modal', - action: 'Show Legal', + modal: ModalName.Legal, }) }, [open]) @@ -99,7 +97,7 @@ export function PrivacyPolicyModal() { - Legal & Privacy + toggle()}> @@ -130,7 +128,7 @@ function PrivacyPolicy() { - Uniswap Labs' Terms of Service + @@ -143,7 +141,7 @@ function PrivacyPolicy() { - Privacy Policy + @@ -152,7 +150,7 @@ function PrivacyPolicy() { - This app uses the following third-party APIs: + {EXTERNAL_APIS.map(({ name, description }, i) => ( @@ -171,7 +169,7 @@ function PrivacyPolicy() { - Learn more + diff --git a/apps/web/src/components/RangeSelector/PresetsButtons.tsx b/apps/web/src/components/RangeSelector/PresetsButtons.tsx index b9108f8988c..f0c0da299b8 100644 --- a/apps/web/src/components/RangeSelector/PresetsButtons.tsx +++ b/apps/web/src/components/RangeSelector/PresetsButtons.tsx @@ -21,7 +21,7 @@ export default function PresetsButtons({ onSetFullRange }: PresetsButtonsProps) diff --git a/apps/web/src/components/RangeSelector/index.tsx b/apps/web/src/components/RangeSelector/index.tsx index 7b087650036..ea867a3d345 100644 --- a/apps/web/src/components/RangeSelector/index.tsx +++ b/apps/web/src/components/RangeSelector/index.tsx @@ -50,7 +50,7 @@ export default function RangeSelector({ incrementDisabled={leftPrice === undefined || ticksAtLimit[isSorted ? Bound.LOWER : Bound.UPPER]} feeAmount={feeAmount} label={leftPrice ? `${currencyB?.symbol}` : '-'} - title={Low price} + title={} tokenA={currencyA?.symbol} tokenB={currencyB?.symbol} /> @@ -65,7 +65,7 @@ export default function RangeSelector({ label={rightPrice ? `${currencyB?.symbol}` : '-'} tokenA={currencyA?.symbol} tokenB={currencyB?.symbol} - title={High price} + title={} /> ) diff --git a/apps/web/src/components/RoutingDiagram/RoutingDiagram.tsx b/apps/web/src/components/RoutingDiagram/RoutingDiagram.tsx index 56ca7584dc6..83fb8ef58b2 100644 --- a/apps/web/src/components/RoutingDiagram/RoutingDiagram.tsx +++ b/apps/web/src/components/RoutingDiagram/RoutingDiagram.tsx @@ -86,7 +86,12 @@ function Pool({ currency0, currency1, feeAmount }: { currency0: Currency; curren // TODO - link pool icon to info.uniswap.org via query params return ( {{ pct: currency0?.symbol + '/' + currency1?.symbol + ' ' + feeAmount / 10000 }}% pool} + text={ + + } size={TooltipSize.ExtraSmall} > diff --git a/apps/web/src/components/SearchModal/CommonBases.tsx b/apps/web/src/components/SearchModal/CommonBases.tsx index 46282cea240..32cd46d8df4 100644 --- a/apps/web/src/components/SearchModal/CommonBases.tsx +++ b/apps/web/src/components/SearchModal/CommonBases.tsx @@ -1,6 +1,5 @@ -import { BrowserEvent, InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' +import { InterfaceElementName } from '@uniswap/analytics-events' import { Currency } from '@uniswap/sdk-core' -import { TraceEvent } from 'analytics' import CurrencyLogo from 'components/Logo/CurrencyLogo' import { AutoRow } from 'components/Row' import { COMMON_BASES } from 'constants/routing' @@ -9,6 +8,8 @@ import { getTokenAddress } from 'lib/utils/analytics' import { Text } from 'rebass' import styled from 'styled-components' import { CurrencyInfo } from 'uniswap/src/features/dataApi/types' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { WalletEventName } from 'uniswap/src/features/telemetry/constants' import { currencyId } from 'utils/currencyId' const BaseWrapper = styled.div<{ disable?: boolean }>` @@ -73,9 +74,10 @@ export default function CommonBases({ const isSelected = selectedCurrency?.equals(currency) return ( - - + ) })} diff --git a/apps/web/src/components/SearchModal/CurrencyList/index.tsx b/apps/web/src/components/SearchModal/CurrencyList/index.tsx index 7b8db8a0400..d13b73eb963 100644 --- a/apps/web/src/components/SearchModal/CurrencyList/index.tsx +++ b/apps/web/src/components/SearchModal/CurrencyList/index.tsx @@ -1,9 +1,10 @@ -import { BrowserEvent, InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' +import { InterfaceElementName } from '@uniswap/analytics-events' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' -import { TraceEvent } from 'analytics' import Loader from 'components/Icons/LoadingSpinner' import TokenSafetyIcon from 'components/TokenSafety/TokenSafetyIcon' +import { useTokenWarning } from 'constants/tokenSafety' +import { useTotalBalancesUsdForAnalytics } from 'graphql/data/apollo/TokenBalancesProvider' import { TokenBalances } from 'lib/hooks/useTokenList/sorting' import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { CSSProperties, MutableRefObject, useCallback } from 'react' @@ -11,11 +12,10 @@ import { FixedSizeList } from 'react-window' import { Text } from 'rebass' import styled from 'styled-components' import { ThemedText } from 'theme/components' -import { NumberType, useFormatter } from 'utils/formatNumbers' - -import { useTokenWarning } from 'constants/tokenSafety' -import { useTotalBalancesUsdForAnalytics } from 'graphql/data/apollo/TokenBalancesProvider' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { WalletEventName } from 'uniswap/src/features/telemetry/constants' import { shortenAddress } from 'utilities/src/addresses' +import { NumberType, useFormatter } from 'utils/formatNumbers' import { useIsUserAddedToken } from '../../../hooks/Tokens' import { TokenFromList } from '../../../state/lists/tokenFromList' import Column, { AutoColumn } from '../../Column' @@ -100,7 +100,9 @@ function TokenTags({ currency }: { currency: Currency }) { } const tags = currency.tags - if (!tags || tags.length === 0) return + if (!tags || tags.length === 0) { + return + } const tag = tags[0] @@ -164,9 +166,10 @@ export function CurrencyRow({ // only show add or remove buttons if not on selected list return ( - @@ -219,7 +222,7 @@ export function CurrencyRow({ )} - + ) } diff --git a/apps/web/src/components/SearchModal/CurrencySearch.tsx b/apps/web/src/components/SearchModal/CurrencySearch.tsx index f1694b0290f..cabbd34e957 100644 --- a/apps/web/src/components/SearchModal/CurrencySearch.tsx +++ b/apps/web/src/components/SearchModal/CurrencySearch.tsx @@ -1,8 +1,8 @@ import { InterfaceEventName, InterfaceModalName } from '@uniswap/analytics-events' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' -import { Trace } from 'analytics' import { ChainSelector } from 'components/NavBar/ChainSelector' import { useCurrencySearchResults } from 'components/SearchModal/useCurrencySearchResults' +import { useAccount } from 'hooks/useAccount' import useDebounce from 'hooks/useDebounce' import { useOnClickOutside } from 'hooks/useOnClickOutside' import useSelectChain from 'hooks/useSelectChain' @@ -17,9 +17,8 @@ import { FixedSizeList } from 'react-window' import { Text } from 'rebass' import styled, { useTheme } from 'styled-components' import { CloseIcon, ThemedText } from 'theme/components' +import Trace from 'uniswap/src/features/telemetry/Trace' import { isAddress } from 'utilities/src/addresses' -import { useChainId } from 'wagmi' - import Column from '../Column' import Row, { RowBetween } from '../Row' import CommonBases from './CommonBases' @@ -75,7 +74,7 @@ export function CurrencySearch({ ...DEFAULT_CURRENCY_SEARCH_FILTERS, ...filters, } - const chainId = useChainId() + const { chainId } = useAccount() const theme = useTheme() // refs for fixed size lists @@ -111,14 +110,18 @@ export function CurrencySearch({ } } onCurrencySelect(currency, hasWarning) - if (!hasWarning) onDismiss() + if (!hasWarning) { + onDismiss() + } }, [chainId, onCurrencySelect, onDismiss, selectChain] ) // clear the input on open useEffect(() => { - if (isOpen) setSearchQuery('') + if (isOpen) { + setSearchQuery('') + } }, [isOpen]) // manage focus on modal show @@ -160,14 +163,14 @@ export function CurrencySearch({ return ( - Select a token + @@ -248,7 +251,7 @@ export function CurrencySearch({ ) : ( - No results found. + )} diff --git a/apps/web/src/components/SearchModal/useCurrencySearchResults.ts b/apps/web/src/components/SearchModal/useCurrencySearchResults.ts index b21d4e1a5c7..f48712a9c58 100644 --- a/apps/web/src/components/SearchModal/useCurrencySearchResults.ts +++ b/apps/web/src/components/SearchModal/useCurrencySearchResults.ts @@ -4,6 +4,7 @@ import { CurrencySearchFilters } from 'components/SearchModal/CurrencySearch' import { chainIdToBackendChain, useSupportedChainId } from 'constants/chains' import { gqlTokenToCurrencyInfo } from 'graphql/data/types' import { useFallbackListTokens, useToken } from 'hooks/Tokens' +import { useAccount } from 'hooks/useAccount' import { useTokenBalances } from 'hooks/useTokenBalances' import { t } from 'i18next' import { getTokenFilter } from 'lib/hooks/useTokenList/filtering' @@ -19,7 +20,6 @@ import { useTopTokensQuery, } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' import { isSameAddress } from 'utilities/src/addresses' -import { useChainId } from 'wagmi' interface CurrencySearchParams { searchQuery?: string @@ -51,7 +51,7 @@ export function useCurrencySearchResults({ selectedCurrency, otherSelectedCurrency, }: CurrencySearchParams): CurrencySearchResults { - const chainId = useChainId() + const { chainId } = useAccount() const supportedChain = useSupportedChainId(chainId) /** @@ -175,7 +175,9 @@ export function useCurrencySearchResults({ // If there is no query, filter out unselected user-added tokens with no balance. if (isEmpty(searchQuery) && currency instanceof UserAddedToken) { - if (selectedCurrency?.equals(currency) || otherSelectedCurrency?.equals(currency)) return true + if (selectedCurrency?.equals(currency) || otherSelectedCurrency?.equals(currency)) { + return true + } return balanceMap[currency.address.toLowerCase()]?.usdValue > 0 } @@ -211,16 +213,16 @@ export function useCurrencySearchResults({ const finalCurrencyList: CurrencyListRow[] = useMemo(() => { if (!isEmpty(searchQuery) || portfolioTokens.length === 0) { return [ - new CurrencyListSectionTitle(searchQuery ? t`Search results` : t`Popular tokens`), + new CurrencyListSectionTitle(searchQuery ? t('common.searchResults') : t('common.popularTokens')), ...sortedCombinedTokens.map(searchQuery ? searchResultsCurrencyListMapper : currencyListRowMapper), ] } else if (sortedTokensWithoutPortfolio.length === 0) { - return [new CurrencyListSectionTitle(t`Your tokens`), ...portfolioTokens.map(currencyListRowMapper)] + return [new CurrencyListSectionTitle(t('common.yourTokens')), ...portfolioTokens.map(currencyListRowMapper)] } else { return [ - new CurrencyListSectionTitle(t`Your tokens`), + new CurrencyListSectionTitle(t('common.yourTokens')), ...portfolioTokens.map(currencyListRowMapper), - new CurrencyListSectionTitle(t`Popular tokens`), + new CurrencyListSectionTitle(t('common.popularTokens')), ...sortedTokensWithoutPortfolio.map(currencyListRowMapper), ] } diff --git a/apps/web/src/components/Settings/MaxSlippageSettings/index.tsx b/apps/web/src/components/Settings/MaxSlippageSettings/index.tsx index d3cb9f576cb..7d64e13702b 100644 --- a/apps/web/src/components/Settings/MaxSlippageSettings/index.tsx +++ b/apps/web/src/components/Settings/MaxSlippageSettings/index.tsx @@ -111,19 +111,15 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe header={ - Max. slippage + - Your transaction will revert if the price changes unfavorably by more than this percentage. - } - /> + } /> } button={ {userSlippageTolerance === SlippageTolerance.Auto ? ( - Auto + ) : ( formatPercent(userSlippageTolerance) )} @@ -141,7 +137,7 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe isActive={userSlippageTolerance === SlippageTolerance.Auto} > - Auto + @@ -176,11 +172,12 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe {tooLow ? ( - - Slippage below {{ amt: formatPercent(MINIMUM_RECOMMENDED_SLIPPAGE) }} may result in a failed transaction - + ) : ( - Your transaction may be frontrun and result in an unfavorable trade. + )} diff --git a/apps/web/src/components/Settings/MenuButton/index.tsx b/apps/web/src/components/Settings/MenuButton/index.tsx index 2f9da6e9cbe..5b2db7124fa 100644 --- a/apps/web/src/components/Settings/MenuButton/index.tsx +++ b/apps/web/src/components/Settings/MenuButton/index.tsx @@ -1,6 +1,6 @@ import { Settings } from 'components/Icons/Settings' import Row from 'components/Row' -import { t, Trans } from 'i18n' +import { Trans, t } from 'i18n' import { InterfaceTrade } from 'state/routing/types' import { isUniswapXTrade } from 'state/routing/utils' import { useUserSlippageTolerance } from 'state/user/hooks' @@ -67,7 +67,7 @@ const ButtonContent = ({ trade, compact }: { trade?: InterfaceTrade; compact: bo {compact ? ( formatPercent(userSlippageTolerance) ) : ( - {{ amt: formatPercent(userSlippageTolerance) }} slippage + )} @@ -95,7 +95,7 @@ export default function MenuButton({ isActive={isActive} id="open-settings-dialog-button" data-testid="open-settings-dialog-button" - aria-label={t`Transaction Settings`} + aria-label={t('common.transactionSettings')} > diff --git a/apps/web/src/components/Settings/MultipleRoutingOptions.test.tsx b/apps/web/src/components/Settings/MultipleRoutingOptions.test.tsx index d2831685264..276d760509e 100644 --- a/apps/web/src/components/Settings/MultipleRoutingOptions.test.tsx +++ b/apps/web/src/components/Settings/MultipleRoutingOptions.test.tsx @@ -1,12 +1,21 @@ +import { ChainId } from '@uniswap/sdk-core' import MultipleRoutingOptions from 'components/Settings/MultipleRoutingOptions' import { isUniswapXSupportedChain } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import { Provider } from 'jotai' import { mocked } from 'test-utils/mocked' import { fireEvent, render, screen, waitFor } from 'test-utils/render' jest.mock('constants/chains') +jest.mock('hooks/useAccount') describe('Multiple routing options', () => { + beforeEach(() => { + mocked(useAccount).mockReturnValue({ + chainId: ChainId.MAINNET, + } as unknown as ReturnType) + }) + it('optimal routing is enabled by default', () => { mocked(isUniswapXSupportedChain).mockReturnValue(true) render( diff --git a/apps/web/src/components/Settings/MultipleRoutingOptions.tsx b/apps/web/src/components/Settings/MultipleRoutingOptions.tsx index 81cd9de4736..1156d8db39e 100644 --- a/apps/web/src/components/Settings/MultipleRoutingOptions.tsx +++ b/apps/web/src/components/Settings/MultipleRoutingOptions.tsx @@ -5,13 +5,13 @@ import QuestionHelper from 'components/QuestionHelper' import Row, { RowBetween } from 'components/Row' import Toggle from 'components/Toggle' import { isUniswapXSupportedChain } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import { Trans, t } from 'i18n' import { atom, useAtom } from 'jotai' import { ReactNode, useCallback } from 'react' import { RouterPreference } from 'state/routing/types' import styled from 'styled-components' import { ExternalLink, ThemedText } from 'theme/components' -import { useChainId } from 'wagmi' const InlineLink = styled.div` color: ${({ theme }) => theme.accent1}; @@ -80,7 +80,7 @@ function UniswapXPreferenceLabel() { - When available, aggregates liquidity sources for better prices and gas free swaps.{' '} + {' '} Learn more @@ -93,10 +93,10 @@ function UniswapXPreferenceLabel() { } const ROUTE_PREFERENCE_TO_LABEL: Record = { - [RoutePreferenceOption.Optimal]: t`Default trade options`, + [RoutePreferenceOption.Optimal]: t('common.defaultTradeOptions'), [RoutePreferenceOption.UniswapX]: , - [RoutePreferenceOption.v3]: t`v3 pools`, - [RoutePreferenceOption.v2]: t`v2 pools`, + [RoutePreferenceOption.v3]: t('pool.v3'), + [RoutePreferenceOption.v2]: t('pool.v2'), } function RoutePreferenceToggle({ @@ -127,7 +127,7 @@ function RoutePreferenceToggle({ } export default function MultipleRoutingOptions() { - const chainId = useChainId() + const { chainId } = useAccount() const [routePreferenceOptions, setRoutePreferenceOptions] = useAtom(routePreferenceOptionsAtom) const [, setRoutingPreferences] = useAtom(routingPreferencesAtom) const shouldDisableProtocolOptionToggle = @@ -196,12 +196,12 @@ export default function MultipleRoutingOptions() { The Uniswap client selects the cheapest trade option factoring price and network costs.} + text={} subheading={ routePreferenceOptions[RoutePreferenceOption.Optimal] && uniswapXSupportedChain && ( - Includes + ) diff --git a/apps/web/src/components/Settings/RouterPreferenceSettings/index.tsx b/apps/web/src/components/Settings/RouterPreferenceSettings/index.tsx index e64781ec1f3..7b15493cfca 100644 --- a/apps/web/src/components/Settings/RouterPreferenceSettings/index.tsx +++ b/apps/web/src/components/Settings/RouterPreferenceSettings/index.tsx @@ -28,7 +28,7 @@ export default function RouterPreferenceSettings() { - When available, aggregates liquidity sources for better prices and gas free swaps.{' '} + {' '} Learn more diff --git a/apps/web/src/components/Settings/TransactionDeadlineSettings/index.tsx b/apps/web/src/components/Settings/TransactionDeadlineSettings/index.tsx index e5a5fcf9c72..3636a7c06ec 100644 --- a/apps/web/src/components/Settings/TransactionDeadlineSettings/index.tsx +++ b/apps/web/src/components/Settings/TransactionDeadlineSettings/index.tsx @@ -66,14 +66,12 @@ export default function TransactionDeadlineSettings() { header={ - Transaction deadline + - Your transaction will revert if it is pending for more than this period of time.} - /> + } /> } - button={{{ time: deadline / 60 }}m} + button={} > @@ -89,7 +87,7 @@ export default function TransactionDeadlineSettings() { }} /> - minutes + diff --git a/apps/web/src/components/Settings/index.test.tsx b/apps/web/src/components/Settings/index.test.tsx index b86f12f8a69..08082073bac 100644 --- a/apps/web/src/components/Settings/index.test.tsx +++ b/apps/web/src/components/Settings/index.test.tsx @@ -1,16 +1,21 @@ -import { Percent } from '@uniswap/sdk-core' +import { ChainId, Percent } from '@uniswap/sdk-core' import { isUniswapXSupportedChain, useIsSupportedChainId } from 'constants/chains' import { mocked } from 'test-utils/mocked' import { fireEvent, render, screen, waitFor } from 'test-utils/render' +import { useAccount } from 'hooks/useAccount' import SettingsTab from './index' const slippage = new Percent(75, 10_000) jest.mock('constants/chains') +jest.mock('hooks/useAccount') describe('Settings Tab', () => { describe('showRoutingSettings', () => { beforeEach(() => { + mocked(useAccount).mockReturnValue({ + chainId: ChainId.MAINNET, + } as unknown as ReturnType) mocked(useIsSupportedChainId).mockReturnValue(true) }) diff --git a/apps/web/src/components/Settings/index.tsx b/apps/web/src/components/Settings/index.tsx index ea06fc9fb41..1fed626d40f 100644 --- a/apps/web/src/components/Settings/index.tsx +++ b/apps/web/src/components/Settings/index.tsx @@ -21,8 +21,8 @@ import { Divider, ThemedText } from 'theme/components' import { Z_INDEX } from 'theme/zIndex' import { FeatureFlags } from 'uniswap/src/features/gating/flags' import { useFeatureFlag } from 'uniswap/src/features/gating/hooks' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import MaxSlippageSettings from './MaxSlippageSettings' import MenuButton from './MenuButton' import RouterPreferenceSettings from './RouterPreferenceSettings' @@ -117,7 +117,7 @@ export default function SettingsTab({ compact?: boolean hideRoutingSettings?: boolean }) { - const connectedChainId = useChainId() + const { chainId: connectedChainId } = useAccount() const showDeadlineSettings = Boolean(chainId && !L2_CHAIN_IDS.includes(chainId)) const node = useRef(null) const isOpen = useModalIsOpen(ApplicationModal.SETTINGS) @@ -185,7 +185,7 @@ export default function SettingsTab({ - Settings + diff --git a/apps/web/src/components/SwitchLocaleLink/index.tsx b/apps/web/src/components/SwitchLocaleLink/index.tsx index 3ecc8cfea69..9f52123cf4a 100644 --- a/apps/web/src/components/SwitchLocaleLink/index.tsx +++ b/apps/web/src/components/SwitchLocaleLink/index.tsx @@ -27,11 +27,13 @@ export function SwitchLocaleLink() { const { to, onClick } = useLocationLinkProps(targetLocale) - if (!targetLocale || !to) return null + if (!targetLocale || !to) { + return null + } return ( - Uniswap available in: + { onClick?.() diff --git a/apps/web/src/components/Table/index.tsx b/apps/web/src/components/Table/index.tsx index 4e9da5fe0a7..5177953db9a 100644 --- a/apps/web/src/components/Table/index.tsx +++ b/apps/web/src/components/Table/index.tsx @@ -8,8 +8,6 @@ import { getCoreRowModel, useReactTable, } from '@tanstack/react-table' -import { BrowserEvent, SharedEventName } from '@uniswap/analytics-events' -import { TraceEvent, useTrace } from 'analytics' import Loader from 'components/Icons/LoadingSpinner' import { ErrorModal } from 'components/Table/ErrorBox' import useDebounce from 'hooks/useDebounce' @@ -19,6 +17,8 @@ import { ScrollSync, ScrollSyncPane } from 'react-scroll-sync' import { ThemedText } from 'theme/components' import { FadePresence } from 'theme/components/FadePresence' import { Z_INDEX } from 'theme/zIndex' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { CellContainer, DataRow, @@ -63,8 +63,8 @@ function TableBody({ ))} {error && ( Error loading data} - subtitle={Data is unavailable at the moment; we're working on a fix} + header={} + subtitle={} /> )} @@ -76,7 +76,7 @@ function TableBody({ return ( - No data found + ) @@ -95,10 +95,8 @@ function TableBody({ const linkState = rowOriginal.linkState // optional data passed to linked page, accessible via useLocation().state const rowTestId = rowOriginal.testId return ( - ({ ) : ( {cells} )} - + ) })} @@ -232,7 +230,7 @@ export function Table({ }} > - Return to top + @@ -246,7 +244,7 @@ export function Table({ - Loading + diff --git a/apps/web/src/components/Table/styled.tsx b/apps/web/src/components/Table/styled.tsx index 3d3377dbe3c..02b93002790 100644 --- a/apps/web/src/components/Table/styled.tsx +++ b/apps/web/src/components/Table/styled.tsx @@ -259,7 +259,7 @@ export const TokenLinkCell = ({ token }: { token: Token }) => { images={isNative ? undefined : [token.project?.logo?.url]} currencies={isNative ? [nativeCurrency] : undefined} /> - {unwrappedToken?.symbol ?? UNKNOWN} + {unwrappedToken?.symbol ?? } ) diff --git a/apps/web/src/components/Table/utils.ts b/apps/web/src/components/Table/utils.ts index 5ac057a6de5..6dd2253924c 100644 --- a/apps/web/src/components/Table/utils.ts +++ b/apps/web/src/components/Table/utils.ts @@ -1,4 +1,4 @@ -import { useTranslation } from 'i18n' +import { useTranslation } from 'i18n/useTranslation' /** * Displays the time as a human-readable string. diff --git a/apps/web/src/components/Toggle/index.tsx b/apps/web/src/components/Toggle/index.tsx index a50bbc02c8a..78a330f47df 100644 --- a/apps/web/src/components/Toggle/index.tsx +++ b/apps/web/src/components/Toggle/index.tsx @@ -77,7 +77,9 @@ export default function Toggle({ id, bgColor, isActive, disabled, toggle }: Togg const switchToggle = () => { toggle() - if (isInitialToggleLoad) setIsInitialToggleLoad(false) + if (isInitialToggleLoad) { + setIsInitialToggleLoad(false) + } } return ( diff --git a/apps/web/src/components/TokenSafety/TokenSafetyMessage.tsx b/apps/web/src/components/TokenSafety/TokenSafetyMessage.tsx index 6902f3afc11..a527be12361 100644 --- a/apps/web/src/components/TokenSafety/TokenSafetyMessage.tsx +++ b/apps/web/src/components/TokenSafety/TokenSafetyMessage.tsx @@ -58,22 +58,22 @@ export default function TokenSafetyMessage({ const { heading, description } = getWarningCopy(warning, plural, tokenSymbol) return ( - } + text={disabled && } placement={!isMobile ? 'right' : undefined} > { - if (disabled) return + if (disabled) { + return + } onSelectOption(chartType) toggleMenu() }} diff --git a/apps/web/src/components/Tokens/TokenDetails/ChartSection/hooks.ts b/apps/web/src/components/Tokens/TokenDetails/ChartSection/hooks.ts index a5de789cded..ce47a5e9ea0 100644 --- a/apps/web/src/components/Tokens/TokenDetails/ChartSection/hooks.ts +++ b/apps/web/src/components/Tokens/TokenDetails/ChartSection/hooks.ts @@ -83,8 +83,12 @@ export function useTDPPriceChartData( } }) // Avoid modifying the last entry, as it should point to the current price - if (minIndex !== entries.length - 1) entries[minIndex].value = min - if (maxIndex !== entries.length - 1) entries[maxIndex].value = max + if (minIndex !== entries.length - 1) { + entries[minIndex].value = min + } + if (maxIndex !== entries.length - 1) { + entries[maxIndex].value = max + } } // Special case: backend data for OHLC data is currently too granular, so points should be combined, halving the data else if (priceChartType === PriceChartType.CANDLESTICK) { diff --git a/apps/web/src/components/Tokens/TokenDetails/ChartSection/index.tsx b/apps/web/src/components/Tokens/TokenDetails/ChartSection/index.tsx index 3a0940dfa23..4140b57e2f4 100644 --- a/apps/web/src/components/Tokens/TokenDetails/ChartSection/index.tsx +++ b/apps/web/src/components/Tokens/TokenDetails/ChartSection/index.tsx @@ -81,7 +81,7 @@ export type TDPChartState = { disableCandlestickUI: boolean } -const InvalidChartMessage = () => Unable to display historical data for the current token. +const InvalidChartMessage = () => /** Exported to `TDPContext` to fire queries on pageload. `TDPChartState` should be accessed through `useTDPContext` rather than this hook. */ export function useCreateTDPChartState(tokenDBAddress: string | undefined, currencyChainName: Chain): TDPChartState { @@ -188,7 +188,9 @@ function ChartControls() { currentChartType={activeQuery.chartType} onSelectOption={(c) => { setChartType(c) - if (c === ChartType.PRICE) setPriceChartType(PriceChartType.LINE) + if (c === ChartType.PRICE) { + setPriceChartType(PriceChartType.LINE) + } }} /> diff --git a/apps/web/src/components/Tokens/TokenDetails/ChartSection/util.ts b/apps/web/src/components/Tokens/TokenDetails/ChartSection/util.ts index cc19c767b23..13ec02d31ac 100644 --- a/apps/web/src/components/Tokens/TokenDetails/ChartSection/util.ts +++ b/apps/web/src/components/Tokens/TokenDetails/ChartSection/util.ts @@ -48,7 +48,9 @@ export function checkDataQuality( chartType: ChartType, duration: HistoryDuration ): DataQuality { - if (data.length < 3) return DataQuality.INVALID + if (data.length < 3) { + return DataQuality.INVALID + } const timeInMs = data[data.length - 1].time * 1000 const stalenessThreshold = CHART_DURATION_STALE_THRESHOLD_MAP[chartType]?.[duration] if (!stalenessThreshold || Date.now() - timeInMs < stalenessThreshold) { diff --git a/apps/web/src/components/Tokens/TokenDetails/Delta.tsx b/apps/web/src/components/Tokens/TokenDetails/Delta.tsx index c59b6053654..a07f1aa87cf 100644 --- a/apps/web/src/components/Tokens/TokenDetails/Delta.tsx +++ b/apps/web/src/components/Tokens/TokenDetails/Delta.tsx @@ -25,7 +25,9 @@ interface DeltaArrowProps { } export function DeltaArrow({ delta, noColor = false, size = 16 }: DeltaArrowProps) { - if (!isValidDelta(delta)) return null + if (!isValidDelta(delta)) { + return null + } return Math.sign(delta) < 0 ? ( diff --git a/apps/web/src/components/Tokens/TokenDetails/InvalidTokenDetails.tsx b/apps/web/src/components/Tokens/TokenDetails/InvalidTokenDetails.tsx index f550b4b3e8c..ca56c181b2d 100644 --- a/apps/web/src/components/Tokens/TokenDetails/InvalidTokenDetails.tsx +++ b/apps/web/src/components/Tokens/TokenDetails/InvalidTokenDetails.tsx @@ -6,8 +6,8 @@ import { Trans } from 'i18n' import { useNavigate } from 'react-router-dom' import styled from 'styled-components' import { ThemedText } from 'theme/components' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import { ReactComponent as EyeIcon } from '../../../assets/svg/eye.svg' const InvalidDetailsContainer = styled.div` @@ -46,7 +46,7 @@ export default function InvalidTokenDetails({ pageChainId: ChainId isInvalidAddress?: boolean }) { - const chainId = useChainId() + const { chainId } = useAccount() const isSupportedChain = useIsSupportedChainId(chainId) const pageChainIsSupported = useIsSupportedChainId(pageChainId) const navigate = useNavigate() @@ -63,11 +63,11 @@ export default function InvalidTokenDetails({ {isInvalidAddress || isNonExistentToken ? ( <> - This token doesn't exist + navigate('/tokens')}> - Explore tokens + @@ -75,12 +75,15 @@ export default function InvalidTokenDetails({ <> {connectedChainLabel && ( - This token doesn't exist on {{ connectedChainLabel }} + )} selectChain(pageChainId)}> - Switch to {{ label: pageChainIsSupported ? CHAIN_INFO[pageChainId].label : '' }} + diff --git a/apps/web/src/components/Tokens/TokenDetails/MobileBalanceSummaryFooter.tsx b/apps/web/src/components/Tokens/TokenDetails/MobileBalanceSummaryFooter.tsx index efbc71f5e9b..c6b32958504 100644 --- a/apps/web/src/components/Tokens/TokenDetails/MobileBalanceSummaryFooter.tsx +++ b/apps/web/src/components/Tokens/TokenDetails/MobileBalanceSummaryFooter.tsx @@ -104,7 +104,7 @@ export default function MobileBalanceSummaryFooter() { {Boolean(account && pageChainBalance) && ( - Your balance + {formattedGqlBalance} {currency.symbol} @@ -114,7 +114,7 @@ export default function MobileBalanceSummaryFooter() { )} - Swap + ) diff --git a/apps/web/src/components/Tokens/TokenDetails/ShareButton.tsx b/apps/web/src/components/Tokens/TokenDetails/ShareButton.tsx index bff7a96e2ab..4142ec31dff 100644 --- a/apps/web/src/components/Tokens/TokenDetails/ShareButton.tsx +++ b/apps/web/src/components/Tokens/TokenDetails/ShareButton.tsx @@ -65,7 +65,7 @@ export default function ShareButton({ name }: { name: string }) { isOpen={open} toggleOpen={toggleShare} menuLabel={} - tooltipText={t`Share`} + tooltipText={t('common.share')} internalMenuItems={ <> setCopied(currentLocation)}> @@ -75,7 +75,7 @@ export default function ShareButton({ name }: { name: string }) { )} - {isCopied ? Copied : Copy link} + {isCopied ? : } - Share to Twitter + diff --git a/apps/web/src/components/Tokens/TokenDetails/Skeleton.tsx b/apps/web/src/components/Tokens/TokenDetails/Skeleton.tsx index 3b393b668c5..a9191b8419d 100644 --- a/apps/web/src/components/Tokens/TokenDetails/Skeleton.tsx +++ b/apps/web/src/components/Tokens/TokenDetails/Skeleton.tsx @@ -206,12 +206,7 @@ export function getLoadingTitle( {tokenName} ) - return ( - - token data for {{ tokenLink }} - {{ chainSuffix }} - - ) + return } export function LoadingChart() { @@ -258,10 +253,10 @@ function TokenDetailsSkeleton() { - Explore + - Tokens + @@ -294,7 +289,7 @@ function TokenDetailsSkeleton() { {tokenAddress && ( - Loading + {getLoadingTitle(token, tokenAddress, chain.id, chain.urlParam)} )} diff --git a/apps/web/src/components/Tokens/TokenDetails/StatsSection.tsx b/apps/web/src/components/Tokens/TokenDetails/StatsSection.tsx index a2d1cac6be7..af0bdd1587a 100644 --- a/apps/web/src/components/Tokens/TokenDetails/StatsSection.tsx +++ b/apps/web/src/components/Tokens/TokenDetails/StatsSection.tsx @@ -108,28 +108,21 @@ export default function StatsSection(props: StatsSectionProps) { return (
- Stats +
- Total value locked (TVL) is the aggregate amount of the asset available across all Uniswap v3 - liquidity pools. -
- } - title={TVL} + description={} + title={} /> Market capitalization is the total market value of an asset's circulating supply. - } - title={Market cap} + description={} + title={} /> @@ -137,17 +130,13 @@ export default function StatsSection(props: StatsSectionProps) { dataCy="fdv" value={FDV} description={HEADER_DESCRIPTIONS[TokenSortMethod.FULLY_DILUTED_VALUATION]} - title={FDV} + title={} /> - 1 day volume is the amount of the asset that has been traded on Uniswap v3 during the past 24 hours. - - } - title={1 day volume} + description={} + title={} /> @@ -157,15 +146,20 @@ export default function StatsSection(props: StatsSectionProps) { return UNSUPPORTED_METADATA_CHAINS.includes(chainId) ? ( <>
- Stats +
- - Token stats and charts for {{ label }} are available on{' '} - - info.uniswap.org - - + + info.uniswap.org + + ), + }} + /> ) : ( diff --git a/apps/web/src/components/Tokens/TokenDetails/TokenDescription.tsx b/apps/web/src/components/Tokens/TokenDetails/TokenDescription.tsx index cb0f2c6263d..d521bd12733 100644 --- a/apps/web/src/components/Tokens/TokenDetails/TokenDescription.tsx +++ b/apps/web/src/components/Tokens/TokenDetails/TokenDescription.tsx @@ -103,11 +103,11 @@ export function TokenDescription() { return ( - Info + {!currency.isNative && ( - + {shortenAddress(currency.address)} @@ -117,14 +117,18 @@ export function TokenDescription() { - {currency.chainId === ChainId.MAINNET ? Etherscan : Explorer} + {currency.chainId === ChainId.MAINNET ? ( + + ) : ( + + )} {homepageUrl && ( - Website + )} @@ -132,7 +136,7 @@ export function TokenDescription() { - Twitter + )} @@ -140,7 +144,7 @@ export function TokenDescription() { {!description && ( - No token information available + )} {description && ( @@ -158,7 +162,11 @@ export function TokenDescription() { onClick={toggleIsDescriptionTruncated} data-testid="token-description-show-more-button" > - {isDescriptionTruncated ? Show more : Hide} + {isDescriptionTruncated ? ( + + ) : ( + + )} )} @@ -176,17 +184,20 @@ export function TokenDescription() { {sameFee ? ( {currency.symbol}  - fee: {sellFeeString} + +  {sellFeeString} ) : ( <> {currency.symbol}  - buy fee: {buyFeeString} + +  {buyFeeString} {' '} {currency.symbol}  - sell fee: {sellFeeString} + +  {sellFeeString} {' '} )} diff --git a/apps/web/src/components/Tokens/TokenDetails/TokenDetailsHeader.tsx b/apps/web/src/components/Tokens/TokenDetails/TokenDetailsHeader.tsx index 1e10b589f79..915d946eaae 100644 --- a/apps/web/src/components/Tokens/TokenDetails/TokenDetailsHeader.tsx +++ b/apps/web/src/components/Tokens/TokenDetails/TokenDetailsHeader.tsx @@ -131,7 +131,7 @@ export const TokenDetailsHeader = () => { const shareMenuRef = useRef(null) useOnClickOutside(shareMenuRef, isShareModalOpen ? toggleShareModal : undefined) - const tokenSymbolName = currency.symbol ?? Symbol not found + const tokenSymbolName = currency.symbol ?? const explorerUrl = getExplorerLink( currency.chainId, @@ -156,7 +156,7 @@ export const TokenDetailsHeader = () => { - {currency.name ?? Name not found} + {currency.name ?? } {tokenSymbolName} @@ -165,7 +165,12 @@ export const TokenDetailsHeader = () => { {!isMobileScreen || (isMobileScreen && actionsModalIsOpen) ? ( {explorerUrl && ( - + {currency.chainId === ChainId.MAINNET ? ( @@ -175,7 +180,7 @@ export const TokenDetailsHeader = () => { )} {isMobileScreen && ( - Explorer + )} @@ -183,13 +188,18 @@ export const TokenDetailsHeader = () => { )} {homepageUrl && ( - + {isMobileScreen && ( - Website + )} @@ -197,13 +207,18 @@ export const TokenDetailsHeader = () => { )} {twitterUrl && ( - + {isMobileScreen && ( - Twitter + )} @@ -219,7 +234,7 @@ export const TokenDetailsHeader = () => { )} - {isCopied ? Copied : Copy link} + {isCopied ? : } { > - Share to Twitter + diff --git a/apps/web/src/components/Tokens/TokenDetails/index.tsx b/apps/web/src/components/Tokens/TokenDetails/index.tsx index d4ffa78e0bc..c2163ed73bf 100644 --- a/apps/web/src/components/Tokens/TokenDetails/index.tsx +++ b/apps/web/src/components/Tokens/TokenDetails/index.tsx @@ -1,7 +1,6 @@ import { InterfacePageName } from '@uniswap/analytics-events' import { ChainId, Currency } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' -import { Trace } from 'analytics' import { BreadcrumbNavContainer, BreadcrumbNavLink, CurrentPageBreadcrumb } from 'components/BreadcrumbNav' import TokenSafetyMessage from 'components/TokenSafety/TokenSafetyMessage' import TokenSafetyModal from 'components/TokenSafety/TokenSafetyModal' @@ -21,6 +20,7 @@ import { ChevronRight } from 'react-feather' import { useNavigate } from 'react-router-dom' import { CurrencyState } from 'state/swap/types' import styled from 'styled-components' +import Trace from 'uniswap/src/features/telemetry/Trace' import { addressesAreEquivalent } from 'utils/addressesAreEquivalent' import { getInitialLogoUrl } from 'utils/getInitialLogoURL' import { ActivitySection } from './ActivitySection' @@ -45,10 +45,10 @@ function TDPBreadcrumb() { return ( - Explore + - Tokens + @@ -56,7 +56,9 @@ function TDPBreadcrumb() { } function getCurrencyURLAddress(currency?: Currency): string { - if (!currency) return '' + if (!currency) { + return '' + } if (currency.isToken) { return currency.address @@ -93,7 +95,9 @@ function TDPSwapComponent() { const newDefaultToken = tokens.outputCurrency ?? tokens.inputCurrency - if (!newDefaultToken) return + if (!newDefaultToken) { + return + } const preloadedLogoSrc = getInitialLogoUrl( newDefaultToken.wrapped.address, @@ -164,6 +168,7 @@ function TDPAnalytics({ children }: PropsWithChildren) { const { address, currency } = useTDPContext() return ( {children} diff --git a/apps/web/src/components/Tokens/TokenDetails/tables/TransactionsTable.tsx b/apps/web/src/components/Tokens/TokenDetails/tables/TransactionsTable.tsx index 9b7fa67ba89..c913a0c9fec 100644 --- a/apps/web/src/components/Tokens/TokenDetails/tables/TransactionsTable.tsx +++ b/apps/web/src/components/Tokens/TokenDetails/tables/TransactionsTable.tsx @@ -128,7 +128,7 @@ export function TransactionsTable({ {sortState.sortBy === Swap_OrderBy.Timestamp && } - Time + @@ -155,7 +155,7 @@ export function TransactionsTable({ toggleFilterModal={toggleFilterModal} /> - Type + @@ -165,7 +165,7 @@ export function TransactionsTable({ return ( - {isBuy ? Buy : Sell} + {isBuy ? : } ) @@ -214,7 +214,7 @@ export function TransactionsTable({ header: () => ( - For + ), @@ -248,7 +248,7 @@ export function TransactionsTable({ header: () => ( - Wallet + ), diff --git a/apps/web/src/components/Tokens/TokenDetails/tables/__snapshots__/TokenDetailsPoolsTable.test.tsx.snap b/apps/web/src/components/Tokens/TokenDetails/tables/__snapshots__/TokenDetailsPoolsTable.test.tsx.snap index 5b3c589c583..6ad92eac187 100644 --- a/apps/web/src/components/Tokens/TokenDetails/tables/__snapshots__/TokenDetailsPoolsTable.test.tsx.snap +++ b/apps/web/src/components/Tokens/TokenDetails/tables/__snapshots__/TokenDetailsPoolsTable.test.tsx.snap @@ -2,7 +2,23 @@ exports[`TDPPoolTable renders data filled state 1`] = ` - .c3 { + .c29 { + height: 16px; + width: 16px; +} + +.c29 path { + stroke: #FC72FF; + background: #7D7D7D; + fill: none; +} + +.c30 { + -webkit-animation: 2s fvtopB linear infinite; + animation: 2s fvtopB linear infinite; +} + +.c3 { box-sizing: border-box; margin: 0; min-width: 0; @@ -98,22 +114,6 @@ exports[`TDPPoolTable renders data filled state 1`] = ` left: 0; } -.c29 { - height: 16px; - width: 16px; -} - -.c29 path { - stroke: #FC72FF; - background: #7D7D7D; - fill: none; -} - -.c30 { - -webkit-animation: 2s fvtopB linear infinite; - animation: 2s fvtopB linear infinite; -} - .c0 { display: -webkit-box; display: -webkit-flex; @@ -732,7 +732,23 @@ exports[`TDPPoolTable renders data filled state 1`] = ` exports[`TDPPoolTable renders error state 1`] = ` - .c3 { + .c25 { + height: 16px; + width: 16px; +} + +.c25 path { + stroke: #FC72FF; + background: #7D7D7D; + fill: none; +} + +.c26 { + -webkit-animation: 2s fvtopB linear infinite; + animation: 2s fvtopB linear infinite; +} + +.c3 { box-sizing: border-box; margin: 0; min-width: 0; @@ -771,22 +787,6 @@ exports[`TDPPoolTable renders error state 1`] = ` letter-spacing: -0.01em; } -.c25 { - height: 16px; - width: 16px; -} - -.c25 path { - stroke: #FC72FF; - background: #7D7D7D; - fill: none; -} - -.c26 { - -webkit-animation: 2s fvtopB linear infinite; - animation: 2s fvtopB linear infinite; -} - .c0 { display: -webkit-box; display: -webkit-flex; @@ -1864,7 +1864,7 @@ exports[`TDPPoolTable renders error state 1`] = `
- Data is unavailable at the moment; we're working on a fix + Data is unavailable at the moment; we’re working on a fix
@@ -1902,7 +1902,23 @@ exports[`TDPPoolTable renders error state 1`] = ` exports[`TDPPoolTable renders loading state 1`] = ` - .c3 { + .c23 { + height: 16px; + width: 16px; +} + +.c23 path { + stroke: #FC72FF; + background: #7D7D7D; + fill: none; +} + +.c24 { + -webkit-animation: 2s fvtopB linear infinite; + animation: 2s fvtopB linear infinite; +} + +.c3 { box-sizing: border-box; margin: 0; min-width: 0; @@ -1933,22 +1949,6 @@ exports[`TDPPoolTable renders loading state 1`] = ` letter-spacing: -0.01em; } -.c23 { - height: 16px; - width: 16px; -} - -.c23 path { - stroke: #FC72FF; - background: #7D7D7D; - fill: none; -} - -.c24 { - -webkit-animation: 2s fvtopB linear infinite; - animation: 2s fvtopB linear infinite; -} - .c0 { display: -webkit-box; display: -webkit-flex; diff --git a/apps/web/src/components/Tokens/TokenTable/NetworkFilter.tsx b/apps/web/src/components/Tokens/TokenTable/NetworkFilter.tsx index 2ad37893520..cce5f6eade9 100644 --- a/apps/web/src/components/Tokens/TokenTable/NetworkFilter.tsx +++ b/apps/web/src/components/Tokens/TokenTable/NetworkFilter.tsx @@ -1,6 +1,7 @@ import Badge from 'components/Badge' import { DropdownSelector, InternalMenuItem } from 'components/DropdownSelector' import { ChainLogo } from 'components/Logo/ChainLogo' +import { AllNetworksIcon } from 'components/Tokens/TokenTable/icons' import { BACKEND_NOT_YET_SUPPORTED_CHAIN_IDS, BACKEND_SUPPORTED_CHAINS, @@ -9,6 +10,7 @@ import { useIsSupportedChainIdCallback, } from 'constants/chains' import { getSupportedGraphQlChain, supportedChainIdFromGQLChain } from 'graphql/data/util' +import { Trans } from 'i18n' import { ExploreTab } from 'pages/Explore' import { useExploreParams } from 'pages/Explore/redirects' import { useReducer } from 'react' @@ -16,6 +18,8 @@ import { Check } from 'react-feather' import { useNavigate } from 'react-router-dom' import styled, { css, useTheme } from 'styled-components' import { EllipsisStyle } from 'theme/components' +import { FeatureFlags } from 'uniswap/src/features/gating/flags' +import { useFeatureFlag } from 'uniswap/src/features/gating/hooks' const NetworkLabel = styled.div` ${EllipsisStyle} @@ -47,6 +51,7 @@ export default function NetworkFilter() { const navigate = useNavigate() const [isMenuOpen, toggleMenu] = useReducer((s) => !s, false) const isSupportedChainCallaback = useIsSupportedChainIdCallback() + const isMultichainExploreEnabled = useFeatureFlag(FeatureFlags.MultichainExplore) const exploreParams = useExploreParams() const currentChain = getSupportedGraphQlChain(useChainFromUrlParam(), { fallbackToEthereum: true }) @@ -59,11 +64,30 @@ export default function NetworkFilter() { toggleOpen={toggleMenu} menuLabel={ - + {!exploreParams.chainName && isMultichainExploreEnabled ? ( + + ) : ( + + )} } internalMenuItems={ <> + {isMultichainExploreEnabled && ( + { + navigate(`/explore/${tab ?? ExploreTab.Tokens}`) + toggleMenu() + }} + > + + All networks + + {!exploreParams.chainName && } + + )} {BACKEND_SUPPORTED_CHAINS.map((network) => { const chainId = supportedChainIdFromGQLChain(network) const isSupportedChain = isSupportedChainCallaback(chainId) @@ -80,7 +104,9 @@ export default function NetworkFilter() { {chainInfo?.label} - {network === currentChain.backendChain.chain && } + {network === currentChain.backendChain.chain && exploreParams.chainName && ( + + )}
) })} diff --git a/apps/web/src/components/Tokens/TokenTable/SearchBar.tsx b/apps/web/src/components/Tokens/TokenTable/SearchBar.tsx index 7ccc23d4346..ced94a1d939 100644 --- a/apps/web/src/components/Tokens/TokenTable/SearchBar.tsx +++ b/apps/web/src/components/Tokens/TokenTable/SearchBar.tsx @@ -1,5 +1,4 @@ -import { BrowserEvent, InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' -import { TraceEvent } from 'analytics' +import { InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' import searchIcon from 'assets/svg/search.svg' import xIcon from 'assets/svg/x.svg' import useDebounce from 'hooks/useDebounce' @@ -7,7 +6,7 @@ import { t } from 'i18n' import { useAtomValue, useUpdateAtom } from 'jotai/utils' import { useEffect, useState } from 'react' import styled from 'styled-components' - +import Trace from 'uniswap/src/features/telemetry/Trace' import { MEDIUM_MEDIA_BREAKPOINT } from '../constants' import { exploreSearchStringAtom } from '../state' const ICON_SIZE = '20px' @@ -72,7 +71,9 @@ export default function SearchBar({ tab }: { tab?: string }) { useEffect(() => { setLocalFilterString(currentString) - if (currentString) setIsOpen(true) + if (currentString) { + setIsOpen(true) + } }, [currentString]) useEffect(() => { @@ -82,15 +83,17 @@ export default function SearchBar({ tab }: { tab?: string }) { const handleFocus = () => setIsOpen(true) const handleBlur = () => { - if (localFilterString === '') setIsOpen(false) + if (localFilterString === '') { + setIsOpen(false) + } } return ( {/* TODO need to figure out new style for this */} - - + ) } diff --git a/apps/web/src/components/Tokens/TokenTable/TimeSelector.tsx b/apps/web/src/components/Tokens/TokenTable/TimeSelector.tsx index 88adc87134d..77a740bb556 100644 --- a/apps/web/src/components/Tokens/TokenTable/TimeSelector.tsx +++ b/apps/web/src/components/Tokens/TokenTable/TimeSelector.tsx @@ -68,7 +68,7 @@ export default function TimeSelector() { toggleOpen={toggleMenu} menuLabel={ <> - {DISPLAYS[activeTime]} {isLargeScreen && volume} + {DISPLAYS[activeTime]} {isLargeScreen && } } internalMenuItems={ @@ -83,7 +83,7 @@ export default function TimeSelector() { }} >
- {DISPLAYS[time]} volume + {DISPLAYS[time]}
{time === activeTime && } diff --git a/apps/web/src/components/Tokens/TokenTable/icons.tsx b/apps/web/src/components/Tokens/TokenTable/icons.tsx new file mode 100644 index 00000000000..306e68377c9 --- /dev/null +++ b/apps/web/src/components/Tokens/TokenTable/icons.tsx @@ -0,0 +1,36 @@ +export const AllNetworksIcon = () => ( + + + + + + + + + + +) diff --git a/apps/web/src/components/Tokens/TokenTable/index.tsx b/apps/web/src/components/Tokens/TokenTable/index.tsx index 8afc3bc8fbb..3a827b3596f 100644 --- a/apps/web/src/components/Tokens/TokenTable/index.tsx +++ b/apps/web/src/components/Tokens/TokenTable/index.tsx @@ -66,7 +66,7 @@ function TokenDescription({ token }: { token: TopToken }) { return ( - {token?.name} + {token?.project?.name ?? token?.name} {token?.symbol} ) @@ -91,25 +91,19 @@ export function TopTokensTable() { } const HEADER_TEXT: Record = { - [TokenSortMethod.FULLY_DILUTED_VALUATION]: FDV, - [TokenSortMethod.PRICE]: Price, - [TokenSortMethod.VOLUME]: Volume, - [TokenSortMethod.HOUR_CHANGE]: 1 hour, - [TokenSortMethod.DAY_CHANGE]: 1 day, + [TokenSortMethod.FULLY_DILUTED_VALUATION]: , + [TokenSortMethod.PRICE]: , + [TokenSortMethod.VOLUME]: , + [TokenSortMethod.HOUR_CHANGE]: , + [TokenSortMethod.DAY_CHANGE]: , } export const HEADER_DESCRIPTIONS: Record = { [TokenSortMethod.PRICE]: undefined, [TokenSortMethod.DAY_CHANGE]: undefined, [TokenSortMethod.HOUR_CHANGE]: undefined, - [TokenSortMethod.FULLY_DILUTED_VALUATION]: ( - - Fully diluted valuation (FDV) calculates the total market value assuming all tokens are in circulation. - - ), - [TokenSortMethod.VOLUME]: ( - Volume is the amount of the asset that has been traded on Uniswap v3 during the selected time frame. - ), + [TokenSortMethod.FULLY_DILUTED_VALUATION]: , + [TokenSortMethod.VOLUME]: , } function TokenTableHeader({ @@ -245,7 +239,7 @@ function TokenTable({ header: () => ( - Token name + ), diff --git a/apps/web/src/components/TransactionConfirmationModal/index.tsx b/apps/web/src/components/TransactionConfirmationModal/index.tsx index 103135e2396..21220f52829 100644 --- a/apps/web/src/components/TransactionConfirmationModal/index.tsx +++ b/apps/web/src/components/TransactionConfirmationModal/index.tsx @@ -4,7 +4,7 @@ import Badge from 'components/Badge' import { ChainLogo } from 'components/Logo/ChainLogo' import { CHAIN_INFO, SupportedL2ChainId, useIsSupportedChainId } from 'constants/chains' import { useCurrencyInfo } from 'hooks/Tokens' -import { Trans, t } from 'i18n' +import { Trans } from 'i18n' import { ReactNode, useCallback, useState } from 'react' import { AlertCircle, ArrowUpCircle, CheckCircle } from 'react-feather' import { isConfirmedTx, useTransaction } from 'state/transactions/hooks' @@ -12,8 +12,8 @@ import styled, { useTheme } from 'styled-components' import { CloseIcon, CustomLightSpinner, ExternalLink, ThemedText } from 'theme/components' import { isL2ChainId } from 'utils/chains' import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import { TransactionStatus } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' import Circle from '../../assets/images/blue-loader.svg' import { TransactionSummary } from '../AccountDetails/TransactionSummary' @@ -67,13 +67,13 @@ function ConfirmationPendingContent({
- Waiting for confirmation + {pendingText} - Confirm this transaction in your wallet + @@ -103,7 +103,9 @@ function TransactionSubmittedContent({ const [success, setSuccess] = useState() const addToken = useCallback(() => { - if (!token?.symbol || !connector.watchAsset) return + if (!token?.symbol || !connector.watchAsset) { + return + } connector .watchAsset({ address: token.address, @@ -115,7 +117,12 @@ function TransactionSubmittedContent({ .catch(() => setSuccess(false)) }, [connector, logoURL, token]) - const explorerText = chainId === ChainId.MAINNET ? t`View on Etherscan` : t`View on Block Explorer` + const explorerText = + chainId === ChainId.MAINNET ? ( + + ) : ( + + ) return ( @@ -131,17 +138,23 @@ function TransactionSubmittedContent({ - Transaction submitted + {currencyToAdd && connector.watchAsset && ( {!success ? ( - Add {{ sym: currencyToAdd.symbol }} + ) : ( - Added {{ sym: currencyToAdd.symbol }} + )} @@ -149,7 +162,7 @@ function TransactionSubmittedContent({ )} - {inline ? Return : Close} + {inline ? : } {chainId && hash && ( @@ -252,13 +265,13 @@ function L2Content({ {!hash ? ( - Confirm transaction in wallet + ) : !confirmed ? ( - Transaction submitted + ) : transactionSuccess ? ( - Success + ) : ( - Error + )} @@ -267,7 +280,7 @@ function L2Content({ {chainId && hash ? ( - View on Explorer + ) : ( @@ -278,7 +291,7 @@ function L2Content({
) : (
- Transaction completed in + {secondsToConfirm} seconds 🎉 @@ -286,7 +299,7 @@ function L2Content({ )} - {inline ? Return : Close} + {inline ? : } @@ -313,10 +326,12 @@ export default function TransactionConfirmationModal({ reviewContent, currencyToAdd, }: ConfirmationModalProps) { - const chainId = useChainId() + const { chainId } = useAccount() const isSupportedChain = useIsSupportedChainId(chainId) - if (!chainId || !isSupportedChain) return null + if (!chainId || !isSupportedChain) { + return null + } // confirmation screen return ( diff --git a/apps/web/src/components/Unicon/index.tsx b/apps/web/src/components/Unicon/index.tsx index 60ec6e6089e..74e75ecaace 100644 --- a/apps/web/src/components/Unicon/index.tsx +++ b/apps/web/src/components/Unicon/index.tsx @@ -111,7 +111,9 @@ function UniconSvg({ viewBox: `0 0 ${size} ${size}`, } - if (!attributeIndices || !attributeData) return null + if (!attributeIndices || !attributeData) { + return null + } return ( @@ -148,7 +150,9 @@ interface Props { function _Unicon({ address, size = 24, randomSeed = 0, mobile }: Props) { const attributeIndices = useMemo(() => deriveUniconAttributeIndices(address, randomSeed), [address, randomSeed]) - if (!address || !isEthAddress(address) || !attributeIndices) return null + if (!address || !isEthAddress(address) || !attributeIndices) { + return null + } return (
diff --git a/apps/web/src/components/Unicon/utils.ts b/apps/web/src/components/Unicon/utils.ts index 2ff7bf94e6f..a186790cc39 100644 --- a/apps/web/src/components/Unicon/utils.ts +++ b/apps/web/src/components/Unicon/utils.ts @@ -22,7 +22,9 @@ export const deriveUniconAttributeIndices = ( address: string, randomSeed = 0 ): UniconAttributesToIndices | undefined => { - if (!isEthAddress(address)) return + if (!isEthAddress(address)) { + return + } const hexAddr = address.slice(-40) const newIndices = { diff --git a/apps/web/src/components/V2Unsupported/index.tsx b/apps/web/src/components/V2Unsupported/index.tsx index 571ac4880dc..8bdcc511c8f 100644 --- a/apps/web/src/components/V2Unsupported/index.tsx +++ b/apps/web/src/components/V2Unsupported/index.tsx @@ -19,7 +19,7 @@ export function V2Unsupported() { - Uniswap V2 is not available on this network. + diff --git a/apps/web/src/components/WalletModal/ConnectionErrorView.tsx b/apps/web/src/components/WalletModal/ConnectionErrorView.tsx index ab6a929ca74..334b1f84e30 100644 --- a/apps/web/src/components/WalletModal/ConnectionErrorView.tsx +++ b/apps/web/src/components/WalletModal/ConnectionErrorView.tsx @@ -31,7 +31,9 @@ export default function ConnectionErrorView({ const { variables, connect, reset } = connectWithLogs const connector = variables?.connector const retry = useCallback(() => { - if (!connector) return + if (!connector) { + return + } if (typeof connector === 'function') { console.warn('a createConnectorFn was passed to the connect() function, rather than a Connector instance') @@ -45,19 +47,17 @@ export default function ConnectionErrorView({ - Error connecting + - - The connection attempt failed. Please click try again and follow the steps to connect in your wallet. - + - Try again + - Back to wallet selection + diff --git a/apps/web/src/components/WalletModal/Option.tsx b/apps/web/src/components/WalletModal/Option.tsx index a587c9444b2..2449558ffae 100644 --- a/apps/web/src/components/WalletModal/Option.tsx +++ b/apps/web/src/components/WalletModal/Option.tsx @@ -1,16 +1,16 @@ -import { BrowserEvent, InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' -import { TraceEvent } from 'analytics' +import { InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' import Badge, { BadgeVariant } from 'components/Badge' import Loader from 'components/Icons/LoadingSpinner' - import { CONNECTOR_ICON_OVERRIDE_MAP, useRecentConnectorId } from 'components/Web3Provider/constants' import { useConnectWithLogs } from 'connection/activate' +import { useAccount } from 'hooks/useAccount' import { Trans } from 'i18n' import styled from 'styled-components' import { ThemedText } from 'theme/components' import { flexColumnNoWrap, flexRowNoWrap } from 'theme/styles' +import Trace from 'uniswap/src/features/telemetry/Trace' import { isIFramed } from 'utils/isIFramed' -import { Connector, useAccount } from 'wagmi' +import { Connector } from 'wagmi' const OptionCardLeft = styled.div` ${flexColumnNoWrap}; @@ -86,7 +86,7 @@ const StyledBadge = styled(Badge)` const RecentBadge = () => ( - Recent + ) @@ -109,9 +109,9 @@ export function Option({ return ( - @@ -129,7 +129,7 @@ export function Option({ {rightSideDetail} - + ) } diff --git a/apps/web/src/components/WalletModal/PrivacyPolicyNotice.tsx b/apps/web/src/components/WalletModal/PrivacyPolicyNotice.tsx index e817b0bf55b..1e492c6801c 100644 --- a/apps/web/src/components/WalletModal/PrivacyPolicyNotice.tsx +++ b/apps/web/src/components/WalletModal/PrivacyPolicyNotice.tsx @@ -10,13 +10,13 @@ const StyledLink = styled(ExternalLink)` export default function PrivacyPolicyNotice() { return ( - By connecting a wallet, you agree to Uniswap Labs'{' '} + - Terms of Service{' '} + {' '} - and consent to its{' '} + {' '} - Privacy Policy. + ) diff --git a/apps/web/src/components/WalletModal/UniswapWalletOptions.tsx b/apps/web/src/components/WalletModal/UniswapWalletOptions.tsx index 5319742409e..8ce00557224 100644 --- a/apps/web/src/components/WalletModal/UniswapWalletOptions.tsx +++ b/apps/web/src/components/WalletModal/UniswapWalletOptions.tsx @@ -53,12 +53,12 @@ export function UniswapWalletOptions({ - Uniswap Extension + - Detected + @@ -68,10 +68,10 @@ export function UniswapWalletOptions({ - Mobile Wallet + - Scan QR code to connect + diff --git a/apps/web/src/components/WalletModal/index.tsx b/apps/web/src/components/WalletModal/index.tsx index 8f7e07c9d84..f542ad26e07 100644 --- a/apps/web/src/components/WalletModal/index.tsx +++ b/apps/web/src/components/WalletModal/index.tsx @@ -68,7 +68,7 @@ export default function WalletModal({ openSettings }: { openSettings: () => void - Other wallets + @@ -94,7 +94,7 @@ export default function WalletModal({ openSettings }: { openSettings: () => void - Fiat onramp powered by MoonPay USA LLC + diff --git a/apps/web/src/components/WalletModal/useOrderedConnections.tsx b/apps/web/src/components/WalletModal/useOrderedConnections.tsx index 1a8fbe400b8..8d5c1251487 100644 --- a/apps/web/src/components/WalletModal/useOrderedConnections.tsx +++ b/apps/web/src/components/WalletModal/useOrderedConnections.tsx @@ -41,7 +41,9 @@ function getInjectedConnectors(connectors: readonly Connector[], excludeUniswapC const injectedConnectors = connectors.filter((c) => { // Special-case: Ignore coinbase eip6963-injected connector; coinbase connection is handled via the SDK connector. if (c.id === CONNECTION.COINBASE_RDNS) { - if (isMobile) isCoinbaseWalletBrowser = true + if (isMobile) { + isCoinbaseWalletBrowser = true + } return false } @@ -68,9 +70,13 @@ export function useOrderedConnections(excludeUniswapConnections?: boolean) { const sortByRecent = useCallback( (a: Connector, b: Connector) => { - if (a.id === recentConnectorId) return -1 - else if (b.id === recentConnectorId) return 1 - else return 0 + if (a.id === recentConnectorId) { + return -1 + } else if (b.id === recentConnectorId) { + return 1 + } else { + return 0 + } }, [recentConnectorId] ) @@ -90,16 +96,22 @@ export function useOrderedConnections(excludeUniswapConnections?: boolean) { } // Special-case: Only display the injected connector for in-wallet browsers. - if (isMobile && injectedConnectors.length === 1) return injectedConnectors + if (isMobile && injectedConnectors.length === 1) { + return injectedConnectors + } // Special-case: Only display the Coinbase connector in the Coinbase Wallet. - if (isCoinbaseWalletBrowser) return [coinbaseSdkConnector] + if (isCoinbaseWalletBrowser) { + return [coinbaseSdkConnector] + } const orderedConnectors: Connector[] = [] const shouldDisplayUniswapWallet = !excludeUniswapConnections && (isWebIOS || isWebAndroid || !isTouchable) // Place the Uniswap Wallet at the top of the list by default. - if (shouldDisplayUniswapWallet) orderedConnectors.push(uniswapWalletConnectConnector) + if (shouldDisplayUniswapWallet) { + orderedConnectors.push(uniswapWalletConnectConnector) + } // Injected connectors should appear next in the list, as the user intentionally installed/uses them. orderedConnectors.push(...injectedConnectors) diff --git a/apps/web/src/components/Web3Provider/index.test.tsx b/apps/web/src/components/Web3Provider/index.test.tsx index 4c8e4a19948..f641fbf2c4c 100644 --- a/apps/web/src/components/Web3Provider/index.test.tsx +++ b/apps/web/src/components/Web3Provider/index.test.tsx @@ -1,14 +1,11 @@ import { InterfaceEventName, WalletConnectionResult } from '@uniswap/analytics-events' -import { sendAnalyticsEvent, user } from 'analytics' +import { useAccount } from 'hooks/useAccount' import { mocked } from 'test-utils/mocked' import { render } from 'test-utils/render' -import { useAccount } from 'wagmi' - -jest.mock('wagmi', () => ({ - ...jest.requireActual('wagmi'), - useAccount: jest.fn(), -})) +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { setUserProperty } from 'uniswap/src/features/telemetry/user' +jest.mock('hooks/useAccount') jest.mock('hooks/useEthersProvider', () => ({ useEthersWeb3Provider: () => { return { provider: {}, off: jest.fn(), send: jest.fn().mockResolvedValue('v1') } @@ -20,10 +17,12 @@ const ACCOUNT2 = '0x0000000000000000000000000000000000000001' const account1Result = { address: ACCOUNT1, connector: { name: 'test' } } as unknown as ReturnType const account2Result = { address: ACCOUNT2, connector: { name: 'test' } } as unknown as ReturnType -jest.mock('analytics', () => ({ - useTrace: jest.fn(), +jest.mock('uniswap/src/features/telemetry/send', () => ({ sendAnalyticsEvent: jest.fn(), - user: { set: jest.fn(), postInsert: jest.fn() }, +})) + +jest.mock('uniswap/src/features/telemetry/user', () => ({ + setUserProperty: jest.fn(), })) function first(array: T[]): T { @@ -43,6 +42,7 @@ describe('Web3Provider', () => { // Assert expect(sendAnalyticsEvent).toHaveBeenCalledTimes(1) + expect(setUserProperty).toHaveBeenCalledTimes(4) expect(sendAnalyticsEvent).toHaveBeenCalledWith(InterfaceEventName.WALLET_CONNECTED, { result: WalletConnectionResult.SUCCEEDED, wallet_address: '0x0000000000000000000000000000000000000000', @@ -51,10 +51,7 @@ describe('Web3Provider', () => { peer_wallet_agent: '(Injected)', }) expect(first(mocked(sendAnalyticsEvent).mock.invocationCallOrder)).toBeGreaterThan( - last(mocked(user.set).mock.invocationCallOrder) - ) - expect(first(mocked(sendAnalyticsEvent).mock.invocationCallOrder)).toBeGreaterThan( - last(mocked(user.postInsert).mock.invocationCallOrder) + last(mocked(setUserProperty).mock.invocationCallOrder) ) }) diff --git a/apps/web/src/components/Web3Provider/index.tsx b/apps/web/src/components/Web3Provider/index.tsx index 97faa26c422..7b9f698a270 100644 --- a/apps/web/src/components/Web3Provider/index.tsx +++ b/apps/web/src/components/Web3Provider/index.tsx @@ -1,10 +1,10 @@ import { QueryClientProvider } from '@tanstack/react-query' import { CustomUserProperties, InterfaceEventName, WalletConnectionResult } from '@uniswap/analytics-events' -import { sendAnalyticsEvent, useTrace, user } from 'analytics' import { recentConnectorIdAtom } from 'components/Web3Provider/constants' import { queryClient, wagmiConfig } from 'components/Web3Provider/wagmi' import { useIsSupportedChainId } from 'constants/chains' import { RPC_PROVIDERS } from 'constants/providers' +import { useAccount } from 'hooks/useAccount' import { useEthersWeb3Provider } from 'hooks/useEthersProvider' import usePrevious from 'hooks/usePrevious' import { useUpdateAtom } from 'jotai/utils' @@ -13,9 +13,12 @@ import { useLocation } from 'react-router-dom' import { useConnectedWallets } from 'state/wallets/hooks' import { FeatureFlags } from 'uniswap/src/features/gating/flags' import { useFeatureFlag } from 'uniswap/src/features/gating/hooks' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { setUserProperty } from 'uniswap/src/features/telemetry/user' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { getCurrentPageFromLocation } from 'utils/urlRoutes' import { getWalletMeta } from 'utils/walletMeta' -import { WagmiProvider, useAccount } from 'wagmi' +import { WagmiProvider } from 'wagmi' export default function Web3Provider({ children }: { children: ReactNode }) { return ( @@ -42,7 +45,9 @@ function Updater() { const updateRecentConnectorId = useUpdateAtom(recentConnectorIdAtom) useEffect(() => { - if (connector) updateRecentConnectorId(connector.id) + if (connector) { + updateRecentConnectorId(connector.id) + } }, [connector, updateRecentConnectorId]) // Trace RPC calls (for debugging). @@ -90,7 +95,7 @@ function Updater() { provider ?.send('web3_clientVersion', []) .then((clientVersion) => { - user.set(CustomUserProperties.WALLET_VERSION, clientVersion) + setUserProperty(CustomUserProperties.WALLET_VERSION, clientVersion) }) .catch((error) => { console.warn('Failed to get client version', error) @@ -98,14 +103,14 @@ function Updater() { // User properties *must* be set before sending corresponding event properties, // so that the event contains the correct and up-to-date user properties. - user.set(CustomUserProperties.WALLET_ADDRESS, account) - user.postInsert(CustomUserProperties.ALL_WALLET_ADDRESSES_CONNECTED, account) + setUserProperty(CustomUserProperties.WALLET_ADDRESS, account) + setUserProperty(CustomUserProperties.ALL_WALLET_ADDRESSES_CONNECTED, account, true) - user.set(CustomUserProperties.WALLET_TYPE, walletType) - user.set(CustomUserProperties.PEER_WALLET_AGENT, peerWalletAgent ?? '') + setUserProperty(CustomUserProperties.WALLET_TYPE, walletType) + setUserProperty(CustomUserProperties.PEER_WALLET_AGENT, peerWalletAgent ?? '') if (chainId) { - user.set(CustomUserProperties.CHAIN_ID, chainId) - user.postInsert(CustomUserProperties.ALL_WALLET_CHAIN_IDS, chainId) + setUserProperty(CustomUserProperties.CHAIN_ID, chainId) + setUserProperty(CustomUserProperties.ALL_WALLET_CHAIN_IDS, chainId, true) } sendAnalyticsEvent(InterfaceEventName.WALLET_CONNECTED, { @@ -125,7 +130,9 @@ function Updater() { } function trace(event: any) { - if (!event?.request) return + if (!event?.request) { + return + } const { method, id, params } = event.request console.groupCollapsed(method, id) console.debug(params) diff --git a/apps/web/src/components/Web3Provider/wagmi.ts b/apps/web/src/components/Web3Provider/wagmi.ts index 17c960623e5..89bdd64c56c 100644 --- a/apps/web/src/components/Web3Provider/wagmi.ts +++ b/apps/web/src/components/Web3Provider/wagmi.ts @@ -1,68 +1,22 @@ import { QueryClient } from '@tanstack/react-query' import { ChainId } from '@uniswap/sdk-core' -import { CHAIN_INFO, SupportedInterfaceChainId } from 'constants/chains' +import { CHAIN_INFO } from 'constants/chains' import { UNISWAP_LOGO } from 'ui/src/assets' -import { Chain, createClient, defineChain } from 'viem' +import { createClient } from 'viem' import { createConfig, http } from 'wagmi' import { connect } from 'wagmi/actions' -import { - arbitrum, - arbitrumGoerli, - avalanche, - base, - blast, - bsc, - celo, - celoAlfajores, - goerli, - mainnet, - optimism, - optimismGoerli, - polygon, - polygonMumbai, - sepolia, -} from 'wagmi/chains' import { coinbaseWallet, injected, safe, walletConnect } from 'wagmi/connectors' import { injectedWithFallback } from './injectedWithFallback' import { WC_PARAMS, uniswapWalletConnect } from './walletConnect' -const CHAIN_ID_TO_VIEM_CHAIN: Record = { - [ChainId.MAINNET]: mainnet, - [ChainId.GOERLI]: goerli, - [ChainId.SEPOLIA]: sepolia, - [ChainId.POLYGON]: polygon, - [ChainId.POLYGON_MUMBAI]: polygonMumbai, - [ChainId.CELO]: celo, - [ChainId.CELO_ALFAJORES]: celoAlfajores, - [ChainId.ARBITRUM_ONE]: arbitrum, - [ChainId.ARBITRUM_GOERLI]: arbitrumGoerli, - [ChainId.OPTIMISM]: optimism, - [ChainId.OPTIMISM_GOERLI]: optimismGoerli, - [ChainId.BNB]: bsc, - [ChainId.AVALANCHE]: avalanche, - [ChainId.BASE]: base, - [ChainId.BLAST]: blast, -} as const - -/** Converts a Chain to use our public RPC URL instead of the default wagmi URL. */ -function withPublicRpcUrls(chain: Chain & { id: SupportedInterfaceChainId }): Chain { - const info = CHAIN_INFO[chain.id] - return defineChain({ - ...chain, - // Match MetaMask's expectations to avoid warnings. - // Expectations are derived from MetaMask's "Safe" list: https://chainid.network/chains.json. - name: info.safeLabel ?? chain.name, - rpcUrls: { default: { http: info.rpcUrls.safe } }, - }) +declare module 'wagmi' { + interface Register { + config: typeof wagmiConfig + } } -/** Converts a Chain to use our private RPC URL instead of the default wagmi URL. */ -function withAppRpcUrls(chain: Chain & { id: SupportedInterfaceChainId }): Chain { - const info = CHAIN_INFO[chain.id] - return defineChain({ ...chain, rpcUrls: { default: { http: info.rpcUrls.appOnly } } }) -} export const wagmiConfig = createConfig({ - chains: [withPublicRpcUrls(mainnet), ...Object.values(CHAIN_ID_TO_VIEM_CHAIN).map(withPublicRpcUrls)], + chains: [CHAIN_INFO[ChainId.MAINNET], ...Object.values(CHAIN_INFO)], connectors: [ injectedWithFallback(), walletConnect(WC_PARAMS), @@ -76,10 +30,10 @@ export const wagmiConfig = createConfig({ ], client({ chain }) { return createClient({ - chain: withAppRpcUrls(chain), + chain, batch: { multicall: true }, pollingInterval: 12_000, - transport: http(), + transport: http(chain.rpcUrls.appOnly.http[0]), }) }, }) diff --git a/apps/web/src/components/Web3Status/index.tsx b/apps/web/src/components/Web3Status/index.tsx index 1abb18edbbb..c20a283dbb5 100644 --- a/apps/web/src/components/Web3Status/index.tsx +++ b/apps/web/src/components/Web3Status/index.tsx @@ -1,5 +1,4 @@ -import { BrowserEvent, InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' -import { TraceEvent, sendAnalyticsEvent } from 'analytics' +import { InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' import PortfolioDrawer from 'components/AccountDrawer' import { usePendingActivity } from 'components/AccountDrawer/MiniPortfolio/Activity/hooks' import { useAccountDrawer } from 'components/AccountDrawer/MiniPortfolio/hooks' @@ -7,6 +6,7 @@ import Loader, { LoaderV3 } from 'components/Icons/LoadingSpinner' import StatusIcon, { IconWrapper } from 'components/Identicon/StatusIcon' import { PrefetchBalancesWrapper } from 'graphql/data/apollo/TokenBalancesProvider' import { navSearchInputVisibleSize } from 'hooks/screenSize/useScreenSize' +import { useAccount } from 'hooks/useAccount' import { Trans } from 'i18n' import { Portal } from 'nft/components/common/Portal' import { darken } from 'polished' @@ -15,8 +15,9 @@ import { useAppSelector } from 'state/hooks' import styled from 'styled-components' import { flexRowNoWrap } from 'theme/styles' import { Unitag } from 'ui/src/components/icons' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { isIFramed } from 'utils/isIFramed' -import { useAccount } from 'wagmi' import { ButtonSecondary } from '../Button' import { RowBetween } from '../Row' import { useAccountIdentifier } from './useAccountIdentifier' @@ -157,11 +158,7 @@ function Web3StatusInner() { if (address) { return ( - + - {{ pendingActivityCount }} Pending + {' '} @@ -183,13 +180,13 @@ function Web3StatusInner() { )} - + ) } else { return ( - - Connect + - + ) } } diff --git a/apps/web/src/components/Web3Status/useAccountIdentifier.ts b/apps/web/src/components/Web3Status/useAccountIdentifier.ts index 12dc033b16a..5230e105535 100644 --- a/apps/web/src/components/Web3Status/useAccountIdentifier.ts +++ b/apps/web/src/components/Web3Status/useAccountIdentifier.ts @@ -1,9 +1,10 @@ +import { useAccount } from 'hooks/useAccount' import { useAtom } from 'jotai' import { atomWithStorage } from 'jotai/utils' import { useEffect } from 'react' import { useUnitagByAddress } from 'uniswap/src/features/unitags/hooks' import { shortenAddress } from 'utilities/src/addresses' -import { useAccount, useAccountEffect, useEnsName } from 'wagmi' +import { useAccountEffect, useEnsName } from 'wagmi' const recentAccountIdentifierMapAtom = atomWithStorage<{ [account in string]?: { unitag?: string; ensName?: string } @@ -26,11 +27,17 @@ export function useAccountIdentifier() { // Keep the stored account identifiers synced with the latest unitag and ENS name useEffect(() => { - if (!address) return + if (!address) { + return + } updateRecentAccountIdentifierMap((prev) => { const updatedIdentifiers = prev[address] ?? {} - if (unitagResponse) updatedIdentifiers.unitag = unitagResponse.username - if (ensNameResponse) updatedIdentifiers.ensName = ensNameResponse + if (unitagResponse) { + updatedIdentifiers.unitag = unitagResponse.username + } + if (ensNameResponse) { + updatedIdentifiers.ensName = ensNameResponse + } return { ...prev, [address]: updatedIdentifiers, recent: updatedIdentifiers } }) diff --git a/apps/web/src/components/addLiquidity/OutOfSyncWarning.tsx b/apps/web/src/components/addLiquidity/OutOfSyncWarning.tsx index 43c2506182f..b4518fea7e0 100644 --- a/apps/web/src/components/addLiquidity/OutOfSyncWarning.tsx +++ b/apps/web/src/components/addLiquidity/OutOfSyncWarning.tsx @@ -5,13 +5,8 @@ import { Trans } from 'react-i18next' export function OutOfSyncWarning() { return ( Pool out of sync} - subtitle={ - - This pool is out of sync with market prices. Adding liquidity at the suggested ratios may result in loss of - funds. - - } + title={} + subtitle={} link={SupportArticleURL.IMPERMANENT_LOSS} /> ) diff --git a/apps/web/src/components/addLiquidity/OwnershipWarning.tsx b/apps/web/src/components/addLiquidity/OwnershipWarning.tsx index d235b0a61d1..2e84a756594 100644 --- a/apps/web/src/components/addLiquidity/OwnershipWarning.tsx +++ b/apps/web/src/components/addLiquidity/OwnershipWarning.tsx @@ -31,14 +31,11 @@ const OwnershipWarning = ({ ownerAddress }: OwnershipWarningProps) => ( - Warning + - - You are not the owner of this LP position. You will not be able to withdraw the liquidity from this position - unless you own the following address: {{ ownerAddress }} - + ) diff --git a/apps/web/src/components/addLiquidity/PoolWarning.tsx b/apps/web/src/components/addLiquidity/PoolWarning.tsx index 6b92aab9148..56a40be0a14 100644 --- a/apps/web/src/components/addLiquidity/PoolWarning.tsx +++ b/apps/web/src/components/addLiquidity/PoolWarning.tsx @@ -53,7 +53,7 @@ export function PoolWarning({ title, subtitle, link }: PoolWarningProps) { - Learn more + diff --git a/apps/web/src/components/addLiquidity/TokenTaxV3Warning.tsx b/apps/web/src/components/addLiquidity/TokenTaxV3Warning.tsx index 965ab3adf49..d4bac96768e 100644 --- a/apps/web/src/components/addLiquidity/TokenTaxV3Warning.tsx +++ b/apps/web/src/components/addLiquidity/TokenTaxV3Warning.tsx @@ -5,13 +5,8 @@ import { Trans } from 'react-i18next' export function TokenTaxV3Warning() { return ( Token taxes} - subtitle={ - - One or more of these tokens have taxes on transfers. Adding liquidity with V3 may result in loss of funds. Try - using V2 instead. - - } + title={} + subtitle={} link={SupportArticleURL.TOKEN_FEE_ON_TRANSFER} /> ) diff --git a/apps/web/src/components/analytics/index.ts b/apps/web/src/components/analytics/index.ts index 95558297690..041fd3b7441 100644 --- a/apps/web/src/components/analytics/index.ts +++ b/apps/web/src/components/analytics/index.ts @@ -1,5 +1,5 @@ import { InterfaceEventName } from '@uniswap/analytics-events' -import { sendAnalyticsEvent } from 'analytics' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' export function outboundLink({ label }: { label: string }) { sendAnalyticsEvent(InterfaceEventName.EXTERNAL_LINK_CLICK, { diff --git a/apps/web/src/components/claim/AddressClaimModal.tsx b/apps/web/src/components/claim/AddressClaimModal.tsx index 6a4e8237af5..34ebd6b0726 100644 --- a/apps/web/src/components/claim/AddressClaimModal.tsx +++ b/apps/web/src/components/claim/AddressClaimModal.tsx @@ -6,8 +6,8 @@ import styled from 'styled-components' import { CloseIcon, CustomLightSpinner, ExternalLink, ThemedText, UniTokenAnimated } from 'theme/components' import { Text } from 'ui/src' import { shortenAddress } from 'utilities/src/addresses' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import Circle from '../../assets/images/blue-loader.svg' import tokenLogo from '../../assets/images/token-logo.png' import useENS from '../../hooks/useENS' @@ -17,9 +17,9 @@ import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink' import AddressInputPanel from '../AddressInputPanel' import { ButtonPrimary } from '../Button' import { AutoColumn, ColumnCenter } from '../Column' -import { Break, CardBGImage, CardBGImageSmaller, CardNoise, CardSection, DataCard } from '../earn/styled' import Modal from '../Modal' import { RowBetween } from '../Row' +import { Break, CardBGImage, CardBGImageSmaller, CardNoise, CardSection, DataCard } from '../earn/styled' const ContentWrapper = styled(AutoColumn)` width: 100%; @@ -44,7 +44,7 @@ const ConfirmedIcon = styled(ColumnCenter)` ` export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boolean; onDismiss: () => void }) { - const chainId = useChainId() + const { chainId } = useAccount() // state for smart contract input const [typed, setTyped] = useState('') @@ -106,27 +106,24 @@ export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boole - Claim UNI token + - {{ amount }} UNI + {amount} UNI - - Enter an address to trigger a UNI claim. If the address has any claimable UNI it will be sent to them on - submission. - + {parsedAddress && !hasAvailableClaim && ( - Address has no available claim + )} - Claim UNI + @@ -160,16 +157,16 @@ export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boole - {claimConfirmed ? Claimed : Claiming} + {claimConfirmed ? : } {!claimConfirmed && ( - {{ unclaimedUni }} UNI + {unclaimedUni} UNI )} {parsedAddress && ( - for {{ address: shortenAddress(parsedAddress) }} + )} @@ -179,7 +176,7 @@ export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boole 🎉{' '} - Welcome to team Unicorn :) + 🎉 @@ -188,12 +185,12 @@ export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boole )} {attempting && !hash && ( - Confirm this transaction in your wallet + )} {attempting && hash && !claimConfirmed && chainId && hash && ( - View transaction on Explorer + )} diff --git a/apps/web/src/components/swap/DetailLineItem.tsx b/apps/web/src/components/swap/DetailLineItem.tsx index 4adb6f035c8..31641bf25a7 100644 --- a/apps/web/src/components/swap/DetailLineItem.tsx +++ b/apps/web/src/components/swap/DetailLineItem.tsx @@ -35,9 +35,13 @@ function ValueWrapper({ children, lineItem, labelHovered, syncing }: ValueWrappe const { TooltipBody, tooltipSize, loaderWidth } = lineItem const isMobile = useIsMobile() - if (syncing) return + if (syncing) { + return + } - if (!TooltipBody) return {children} + if (!TooltipBody) { + return {children} + } return ( { const { formatNumber } = useFormatter() - if (!amount && !itemValue) return null + if (!amount && !itemValue) { + return null + } const value = itemValue ?? formatNumber({ input: amount, type: NumberType.FiatGasPrice }) return ( @@ -44,7 +46,9 @@ export function GasBreakdownTooltip({ trade }: GasBreakdownTooltipProps) { const inputCurrency = trade.inputAmount.currency const native = nativeOnChain(inputCurrency.chainId) - if (isPreviewTrade(trade)) return + if (isPreviewTrade(trade)) { + return + } const swapEstimate = !isUniswapX ? trade.gasUseEstimateUSD : undefined const approvalEstimate = trade.approveInfo.needsApprove ? trade.approveInfo.approveGasEstimateUSD : undefined @@ -53,18 +57,23 @@ export function GasBreakdownTooltip({ trade }: GasBreakdownTooltipProps) { const description = isUniswapX ? : - if (!showEstimateDetails) return description + if (!showEstimateDetails) { + return description + } return ( - Wrap {{ sym: native.symbol }}} amount={wrapEstimate} /> Allow {{ sym: inputCurrency.symbol }} (one time)} + title={} + amount={wrapEstimate} + /> + } amount={approvalEstimate} /> - Swap} amount={swapEstimate} /> - {isUniswapX && Swap} itemValue={} />} + } amount={swapEstimate} /> + {isUniswapX && } itemValue={} />} {description} @@ -78,11 +87,9 @@ function NetworkCostDescription({ native }: { native: Currency }) { return ( - - Network cost is paid in {{ sym: native.symbol }} on the {{ chainName }} network in order to transact. - {' '} + {' '} - Learn more + ) @@ -94,12 +101,14 @@ const InlineUniswapXGradient = styled(UniswapXGradient)` export function UniswapXDescription() { return ( - - UniswapX aggregates liquidity sources for better prices and gas - free swaps. - {' '} + UniswapX, + }} + />{' '} - Learn more + ) diff --git a/apps/web/src/components/swap/GasEstimateTooltip.tsx b/apps/web/src/components/swap/GasEstimateTooltip.tsx index 9b2fc70bf05..262f2be5d9a 100644 --- a/apps/web/src/components/swap/GasEstimateTooltip.tsx +++ b/apps/web/src/components/swap/GasEstimateTooltip.tsx @@ -1,18 +1,17 @@ import { InterfaceElementName, SwapEventName } from '@uniswap/analytics-events' -import { sendAnalyticsEvent } from 'analytics' import { Gas } from 'components/Icons/Gas' import { LoadingOpacityContainer } from 'components/Loader/styled' import { UniswapXGradient, UniswapXRouterIcon } from 'components/RouterLabel/UniswapXRouterLabel' import Row, { RowFixed } from 'components/Row' import { MouseoverTooltip, TooltipSize } from 'components/Tooltip' import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import { SubmittableTrade } from 'state/routing/types' import { isUniswapXTrade } from 'state/routing/utils' import styled from 'styled-components' import { ThemedText } from 'theme/components' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { NumberType, useFormatter } from 'utils/formatNumbers' -import { useChainId } from 'wagmi' - import { GasBreakdownTooltip } from './GasBreakdownTooltip' const StyledGasIcon = styled(Gas)` @@ -25,7 +24,7 @@ const StyledGasIcon = styled(Gas)` ` export default function GasEstimateTooltip({ trade, loading }: { trade?: SubmittableTrade; loading: boolean }) { - const chainId = useChainId() + const { chainId } = useAccount() const { formatNumber } = useFormatter() if (!trade || !chainId || !SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId)) { diff --git a/apps/web/src/components/swap/LimitDisclaimer.tsx b/apps/web/src/components/swap/LimitDisclaimer.tsx index f184e5b72db..491b7cd160d 100644 --- a/apps/web/src/components/swap/LimitDisclaimer.tsx +++ b/apps/web/src/components/swap/LimitDisclaimer.tsx @@ -18,15 +18,12 @@ export function LimitDisclaimer({ className }: { className?: string }) { return ( - - Please be aware that the execution for limits may vary based on real-time market fluctuations and Ethereum - network congestion. Limits may not execute exactly when tokens reach the specified price. - + Canceling a limit has a network cost. - Learn more + diff --git a/apps/web/src/components/swap/MaxSlippageTooltip.tsx b/apps/web/src/components/swap/MaxSlippageTooltip.tsx index c261a50ad26..f6de0f5e536 100644 --- a/apps/web/src/components/swap/MaxSlippageTooltip.tsx +++ b/apps/web/src/components/swap/MaxSlippageTooltip.tsx @@ -7,24 +7,18 @@ import { ExternalLink, Separator, ThemedText } from 'theme/components' import { NumberType, useFormatter } from 'utils/formatNumbers' const ExactInMessage = ({ amount }: { amount: string }) => ( - - If the price moves so that you will receive less than {{ amount }}, your transaction will be reverted. This is the - minimum amount you are guaranteed to receive. - + ) const ExactOutMessage = ({ amount }: { amount: string }) => ( - - If the price moves so that you will pay more than {{ amount }}, your transaction will be reverted. This is the - maximum amount you are guaranteed to pay. - + ) function SlippageHeader({ amount, isExactIn }: { amount: string; isExactIn: boolean }) { return ( - {isExactIn ? Receive at least : Pay at most} + {isExactIn ? : } {amount} @@ -45,7 +39,7 @@ export function MaxSlippageTooltip({ trade, allowedSlippage }: { trade: Interfac
{isExactIn ? : }{' '} - Learn more +
diff --git a/apps/web/src/components/swap/PriceImpactModal.tsx b/apps/web/src/components/swap/PriceImpactModal.tsx index 85d014e7b4f..c5a44b1feff 100644 --- a/apps/web/src/components/swap/PriceImpactModal.tsx +++ b/apps/web/src/components/swap/PriceImpactModal.tsx @@ -51,24 +51,27 @@ export default function PriceImpactModal({ priceImpact, onDismiss, onContinue }: - Warning + - - This transaction will result in a{' '} - - {impact} - {' '} - price impact on the market price of this pool. Do you wish to continue? - + + {impact} + + ), + }} + /> - Continue + - Cancel + diff --git a/apps/web/src/components/swap/PriceImpactWarning.tsx b/apps/web/src/components/swap/PriceImpactWarning.tsx index 39d94ccb4ba..a673fd6f396 100644 --- a/apps/web/src/components/swap/PriceImpactWarning.tsx +++ b/apps/web/src/components/swap/PriceImpactWarning.tsx @@ -26,18 +26,11 @@ export default function PriceImpactWarning({ priceImpact }: PriceImpactWarningPr return ( - - A swap of this size may have a high price impact, given the current liquidity in the pool. There may be a - large difference between the amount of your input token and what you will receive in the output token -
- } - > + }> - Price impact warning + diff --git a/apps/web/src/components/swap/SwapBuyFiatButton.tsx b/apps/web/src/components/swap/SwapBuyFiatButton.tsx index d1915bad4e6..897ba32ce7b 100644 --- a/apps/web/src/components/swap/SwapBuyFiatButton.tsx +++ b/apps/web/src/components/swap/SwapBuyFiatButton.tsx @@ -1,13 +1,12 @@ -import { BrowserEvent, InterfaceElementName, SharedEventName } from '@uniswap/analytics-events' +import { InterfaceElementName } from '@uniswap/analytics-events' import { useWeb3React } from '@web3-react/core' -import { TraceEvent } from 'analytics' import { useAccountDrawer, useSetShowMoonpayText } from 'components/AccountDrawer/MiniPortfolio/hooks' import { MouseoverTooltip } from 'components/Tooltip' import { Trans } from 'i18n' import { useCallback, useEffect, useState } from 'react' import { ExternalLink } from 'theme/components' +import Trace from 'uniswap/src/features/telemetry/Trace' import { isPathBlocked } from 'utils/blockedPaths' - import { useFiatOnrampAvailability, useOpenModal } from '../../state/application/hooks' import { ApplicationModal } from '../../state/application/reducer' import { SwapHeaderTabButton } from './styled' @@ -97,24 +96,19 @@ export default function SwapBuyFiatButton() { - Crypto purchases are not available in your region. - + + - Learn more + - +
} placement="bottom" disabled={fiatOnRampsUnavailableTooltipDisabled} > - @@ -124,9 +118,9 @@ export default function SwapBuyFiatButton() { disabled={buyCryptoButtonDisabled} data-testid="buy-fiat-button" > - Buy + - + ) } diff --git a/apps/web/src/components/swap/SwapDetails.tsx b/apps/web/src/components/swap/SwapDetails.tsx index f00e9ef3164..68696d96bf3 100644 --- a/apps/web/src/components/swap/SwapDetails.tsx +++ b/apps/web/src/components/swap/SwapDetails.tsx @@ -1,9 +1,9 @@ -import { BrowserEvent, InterfaceElementName, SwapEventName } from '@uniswap/analytics-events' +import { InterfaceElementName, SwapEventName } from '@uniswap/analytics-events' import { Percent } from '@uniswap/sdk-core' -import { TraceEvent, useTrace } from 'analytics' import AnimatedDropdown from 'components/AnimatedDropdown' import Column from 'components/Column' import SpinningLoader from 'components/Loader/SpinningLoader' +import { LimitDisclaimer } from 'components/swap/LimitDisclaimer' import { Allowance, AllowanceState } from 'hooks/usePermit2Allowance' import { SwapResult } from 'hooks/useSwapCallback' import { Trans, t } from 'i18n' @@ -17,10 +17,10 @@ import { isClassicTrade, isLimitTrade } from 'state/routing/utils' import { useRouterPreference, useUserSlippageTolerance } from 'state/user/hooks' import styled, { useTheme } from 'styled-components' import { ExternalLink, Separator, ThemedText } from 'theme/components' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import getRoutingDiagramEntries from 'utils/getRoutingDiagramEntries' import { formatSwapButtonClickEventProperties } from 'utils/loggingFormatters' - -import { LimitDisclaimer } from 'components/swap/LimitDisclaimer' import { ReactComponent as ExpandoIconClosed } from '../../assets/svg/expando-icon-closed.svg' import { ReactComponent as ExpandoIconOpened } from '../../assets/svg/expando-icon-opened.svg' import { ButtonError, SmallButtonPrimary } from '../Button' @@ -87,7 +87,7 @@ function DropdownController({ open, onClick }: { open: boolean; onClick: () => v - {open ? Show less : Show more} + {open ? : } {open ? : } @@ -138,15 +138,15 @@ export function SwapDetails({ const callToAction: CallToAction = useMemo(() => { if (allowance && allowance.state === AllowanceState.REQUIRED && allowance.needsSetupApproval) { return { - buttonText: isLimitTrade(trade) ? t`Approve and submit` : t`Approve and swap`, + buttonText: isLimitTrade(trade) ? t('swap.approveAndSubmit') : t('swap.approveAndSwap'), } } else if (allowance && allowance.state === AllowanceState.REQUIRED && allowance.needsPermitSignature) { return { - buttonText: t`Sign and swap`, + buttonText: t('swap.signAndSwap'), } } else { return { - buttonText: isLimitTrade(trade) ? t`Place order` : t`Confirm swap`, + buttonText: isLimitTrade(trade) ? t('swap.placeOrder') : t('swap.confirmSwap'), } } }, [allowance, trade]) @@ -172,20 +172,20 @@ export function SwapDetails({ - Price updated + - Accept + ) : ( - - Finalizing quote... + ) : ( @@ -221,7 +221,7 @@ export function SwapDetails({ {callToAction.helpLink && ( {callToAction.helpLink.text} )} - + {swapErrorMessage ? : null} @@ -300,7 +300,9 @@ function ExpandableLineItems(props: { }) { const { open, trade, allowedSlippage, priceImpact } = props - if (!trade) return null + if (!trade) { + return null + } const lineItemProps = { trade, allowedSlippage, syncing: false, open, priceImpact } diff --git a/apps/web/src/components/swap/SwapDetailsDropdown.tsx b/apps/web/src/components/swap/SwapDetailsDropdown.tsx index 4f23bc8f63e..28bfde9384b 100644 --- a/apps/web/src/components/swap/SwapDetailsDropdown.tsx +++ b/apps/web/src/components/swap/SwapDetailsDropdown.tsx @@ -1,6 +1,5 @@ -import { BrowserEvent, InterfaceElementName, SwapEventName } from '@uniswap/analytics-events' +import { InterfaceElementName, SwapEventName } from '@uniswap/analytics-events' import { Percent } from '@uniswap/sdk-core' -import { TraceEvent, useTrace } from 'analytics' import AnimatedDropdown from 'components/AnimatedDropdown' import Column from 'components/Column' import { LoadingOpacityContainer } from 'components/Loader/styled' @@ -13,8 +12,9 @@ import { InterfaceTrade } from 'state/routing/types' import { isSubmittableTrade } from 'state/routing/utils' import styled, { useTheme } from 'styled-components' import { ThemedText } from 'theme/components' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { useFormatter } from 'utils/formatNumbers' - import GasEstimateTooltip from './GasEstimateTooltip' import SwapLineItem, { SwapLineItemType } from './SwapLineItem' import TradePrice from './TradePrice' @@ -55,15 +55,15 @@ export default function SwapDetailsDropdown(props: SwapDetailsProps) { return ( - ) : loading || syncing ? ( - Fetching best price... + ) : null} @@ -89,7 +89,7 @@ export default function SwapDetailsDropdown(props: SwapDetailsProps) { - + ) @@ -99,7 +99,9 @@ function AdvancedSwapDetails(props: SwapDetailsProps & { open: boolean }) { const { open, trade, allowedSlippage, syncing = false, priceImpact } = props const format = useFormatter() - if (!trade) return null + if (!trade) { + return null + } const lineItemProps = { trade, allowedSlippage, format, syncing, priceImpact } diff --git a/apps/web/src/components/swap/SwapHeader.test.tsx b/apps/web/src/components/swap/SwapHeader.test.tsx index 94ab3e796e6..2e5ae8882c0 100644 --- a/apps/web/src/components/swap/SwapHeader.test.tsx +++ b/apps/web/src/components/swap/SwapHeader.test.tsx @@ -2,8 +2,9 @@ import { ChainId } from '@uniswap/sdk-core' import { Dispatch, PropsWithChildren, SetStateAction } from 'react' import { CurrencyState, EMPTY_DERIVED_SWAP_INFO, SwapAndLimitContext, SwapContext } from 'state/swap/types' import { act, render, screen } from 'test-utils/render' +import { SwapTab } from 'uniswap/src/types/screens/interface' import SwapHeader from './SwapHeader' -import { Field, SwapTab } from './constants' +import { Field } from './constants' interface WrapperProps { setCurrentTab?: Dispatch> diff --git a/apps/web/src/components/swap/SwapHeader.tsx b/apps/web/src/components/swap/SwapHeader.tsx index 2488bd5d9af..bcfb40f222a 100644 --- a/apps/web/src/components/swap/SwapHeader.tsx +++ b/apps/web/src/components/swap/SwapHeader.tsx @@ -1,15 +1,15 @@ import { Trans } from 'i18n' -import { useSwapAndLimitContext, useSwapContext } from 'state/swap/hooks' -import styled from 'styled-components' - -import { sendAnalyticsEvent } from 'analytics' import { useCallback, useEffect } from 'react' import { useLocation, useNavigate } from 'react-router-dom' +import { useSwapAndLimitContext, useSwapContext } from 'state/swap/hooks' +import styled from 'styled-components' +import { InterfaceEventNameLocal } from 'uniswap/src/features/telemetry/constants' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { SwapTab } from 'uniswap/src/types/screens/interface' import { isIFramed } from 'utils/isIFramed' import { RowBetween, RowFixed } from '../Row' import SettingsTab from '../Settings' import SwapBuyFiatButton from './SwapBuyFiatButton' -import { SwapTab } from './constants' import { SwapHeaderTabButton } from './styled' const StyledSwapHeader = styled(RowBetween)` @@ -46,7 +46,7 @@ export default function SwapHeader({ compact, syncTabToUrl }: { compact: boolean const onTabClick = useCallback( (tab: SwapTab) => { - sendAnalyticsEvent('Swap Tab Clicked', { tab }) + sendAnalyticsEvent(InterfaceEventNameLocal.SwapTabClicked, { tab }) if (syncTabToUrl) { navigate(`/${tab}`, { replace: true }) } else { @@ -68,7 +68,7 @@ export default function SwapHeader({ compact, syncTabToUrl }: { compact: boolean onTabClick(SwapTab.Swap) }} > - Swap + - Limit + {!isIFramed() && ( - Send + )} diff --git a/apps/web/src/components/swap/SwapLineItem.tsx b/apps/web/src/components/swap/SwapLineItem.tsx index 9e16855cfaf..05696fd4521 100644 --- a/apps/web/src/components/swap/SwapLineItem.tsx +++ b/apps/web/src/components/swap/SwapLineItem.tsx @@ -52,39 +52,28 @@ const AutoBadge = styled(ThemedText.LabelMicro).attrs({ fontWeight: 535 })` align-items: center; ::after { - content: '${t`Auto`}'; + content: '${t('commmon.automatic')}'; } ` export function FOTTooltipContent() { return ( <> - - Some tokens take a fee when they are bought or sold, which is set by the token issuer. Uniswap does not receive - any of these fees. - {' '} + {' '} - Learn more + ) } function SwapFeeTooltipContent({ hasFee }: { hasFee: boolean }) { - const message = hasFee ? ( - - Fees are applied to ensure the best experience with Uniswap, and have already been factored into this quote. - - ) : ( - - Fees are applied to ensure the best experience with Uniswap. There is no fee associated with this swap. - - ) + const message = hasFee ? : return ( <> {message}{' '} - Learn more + ) @@ -113,7 +102,9 @@ function FeeRow({ trade: { swapFee, outputAmount } }: { trade: SubmittableTrade const { data: outputFeeFiatValue } = useUSDPrice(feeCurrencyAmount, feeCurrencyAmount?.currency) // Fallback to displaying token amount if fiat value is not available - if (outputFeeFiatValue === undefined) return + if (outputFeeFiatValue === undefined) { + return + } return <>{formatNumber({ input: outputFeeFiatValue, type: NumberType.FiatGasPrice })} } @@ -130,38 +121,46 @@ function useLineItem(props: SwapLineItemProps): LineItemData | undefined { // Tracks the latest submittable trade's fill type, used to 'guess' whether or not to show price impact during preview const [lastSubmittableFillType, setLastSubmittableFillType] = useState() useEffect(() => { - if (trade.fillType !== TradeFillType.None) setLastSubmittableFillType(trade.fillType) + if (trade.fillType !== TradeFillType.None) { + setLastSubmittableFillType(trade.fillType) + } }, [trade.fillType]) switch (type) { case SwapLineItemType.EXCHANGE_RATE: return { - Label: () => (isLimitTrade(trade) ? Limit price : Rate), + Label: () => (isLimitTrade(trade) ? : ), Value: () => , TooltipBody: !isPreview ? () => : undefined, tooltipSize: isUniswapX ? TooltipSize.Small : TooltipSize.Large, } case SwapLineItemType.NETWORK_COST: - if (!SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId)) return + if (!SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId)) { + return + } return { - Label: () => Network cost, + Label: () => , TooltipBody: () => , Value: () => { - if (isPreview) return + if (isPreview) { + return + } return }, } case SwapLineItemType.PRICE_IMPACT: // Hides price impact row if the current trade is UniswapX or we're expecting a preview trade to result in UniswapX - if (isUniswapX || !priceImpact || (isPreview && isUniswapXTradeType(lastSubmittableFillType))) return + if (isUniswapX || !priceImpact || (isPreview && isUniswapXTradeType(lastSubmittableFillType))) { + return + } return { - Label: () => Price impact, - TooltipBody: () => The impact your trade has on the market price of this pool., + Label: () => , + TooltipBody: () => , Value: () => (isPreview ? : ), } case SwapLineItemType.MAX_SLIPPAGE: return { - Label: () => Max. slippage, + Label: () => , TooltipBody: () => , Value: () => ( @@ -170,11 +169,13 @@ function useLineItem(props: SwapLineItemProps): LineItemData | undefined { ), } case SwapLineItemType.SWAP_FEE: { - if (isPreview) return { Label: () => Fee, Value: () => } + if (isPreview) { + return { Label: () => , Value: () => } + } return { Label: () => ( <> - Fee {trade.swapFee && `(${formatPercent(trade.swapFee.percent)})`} + {trade.swapFee && `(${formatPercent(trade.swapFee.percent)})`} ), TooltipBody: () => , @@ -182,37 +183,35 @@ function useLineItem(props: SwapLineItemProps): LineItemData | undefined { } } case SwapLineItemType.MAXIMUM_INPUT: - if (trade.tradeType === TradeType.EXACT_INPUT) return + if (trade.tradeType === TradeType.EXACT_INPUT) { + return + } return { - Label: () => Pay at most, - TooltipBody: () => ( - - The maximum amount you are guaranteed to spend. If the price slips any further, your transaction will - revert. - - ), + Label: () => , + TooltipBody: () => , Value: () => , loaderWidth: 70, } case SwapLineItemType.MINIMUM_OUTPUT: - if (trade.tradeType === TradeType.EXACT_OUTPUT) return + if (trade.tradeType === TradeType.EXACT_OUTPUT) { + return + } return { - Label: () => Receive at least, - TooltipBody: () => ( - - The minimum amount you are guaranteed to receive. If the price slips any further, your transaction will - revert. - - ), + Label: () => , + TooltipBody: () => , Value: () => , loaderWidth: 70, } case SwapLineItemType.ROUTING_INFO: - if (isPreview || syncing) return { Label: () => Order routing, Value: () => } + if (isPreview || syncing) { + return { Label: () => , Value: () => } + } return { - Label: () => Order routing, + Label: () => , TooltipBody: () => { - if (isUniswapX) return + if (isUniswapX) { + return + } return }, tooltipSize: isUniswapX ? TooltipSize.Small : TooltipSize.Large, @@ -222,9 +221,11 @@ function useLineItem(props: SwapLineItemProps): LineItemData | undefined { case SwapLineItemType.OUTPUT_TOKEN_FEE_ON_TRANSFER: return getFOTLineItem(props) case SwapLineItemType.EXPIRY: - if (!isLimitTrade(trade)) return + if (!isLimitTrade(trade)) { + return + } return { - Label: () => Expiry, + Label: () => , Value: () => {formatTimestamp(trade.deadline, true)}, } } @@ -234,10 +235,12 @@ function getFOTLineItem({ type, trade }: SwapLineItemProps): LineItemData | unde const isInput = type === SwapLineItemType.INPUT_TOKEN_FEE_ON_TRANSFER const currency = isInput ? trade.inputAmount.currency : trade.outputAmount.currency const tax = isInput ? trade.inputTax : trade.outputTax - if (tax.equalTo(0)) return + if (tax.equalTo(0)) { + return + } return { - Label: () => <>{t(`{{name}} fee`, { name: currency.symbol ?? currency.name ?? t`Token` })}, + Label: () => <>{t(`swap.namedFee`, { name: currency.symbol ?? currency.name ?? t('common.token') })}, TooltipBody: FOTTooltipContent, Value: () => , } @@ -254,7 +257,9 @@ export interface SwapLineItemProps { function SwapLineItem(props: SwapLineItemProps) { const LineItem = useLineItem(props) - if (!LineItem) return null + if (!LineItem) { + return null + } return ( diff --git a/apps/web/src/components/swap/SwapPreview.tsx b/apps/web/src/components/swap/SwapPreview.tsx index 1cc395076cc..fd7021410e1 100644 --- a/apps/web/src/components/swap/SwapPreview.tsx +++ b/apps/web/src/components/swap/SwapPreview.tsx @@ -31,7 +31,7 @@ export function SwapPreview({ Sell} + label={} amount={trade.inputAmount} currency={inputCurrency ?? trade.inputAmount.currency} usdAmount={fiatValueInput.data} @@ -39,7 +39,7 @@ export function SwapPreview({ /> Buy} + label={} amount={trade.outputAmount} currency={trade.outputAmount.currency} usdAmount={fiatValueOutput.data} @@ -47,31 +47,29 @@ export function SwapPreview({ tooltipText={ trade.tradeType === TradeType.EXACT_INPUT ? ( - - Output is estimated. You will receive at least{' '} - {{ + {trade.minimumAmountOut(allowedSlippage).toSignificant(6)} {trade.outputAmount.currency.symbol} ), - }}{' '} - or the transaction will revert. - + }} + /> ) : ( - - Input is estimated. You will sell at most{' '} - {{ + {trade.maximumAmountIn(allowedSlippage).toSignificant(6)} {trade.inputAmount.currency.symbol} ), - }}{' '} - or the transaction will revert. - + }} + /> ) } diff --git a/apps/web/src/components/swap/SwapRoute.tsx b/apps/web/src/components/swap/SwapRoute.tsx index 7f3fba7caa8..c9f81dde40c 100644 --- a/apps/web/src/components/swap/SwapRoute.tsx +++ b/apps/web/src/components/swap/SwapRoute.tsx @@ -17,7 +17,9 @@ import { UniswapXDescription } from './GasBreakdownTooltip' // Can `trade.gasUseEstimateUSD` be defined when `chainId` is not in `SUPPORTED_GAS_ESTIMATE_CHAIN_IDS`? function useGasPrice({ gasUseEstimateUSD, inputAmount }: ClassicTrade) { const { formatNumber } = useFormatter() - if (!gasUseEstimateUSD || !SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(inputAmount.currency.chainId)) return undefined + if (!gasUseEstimateUSD || !SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(inputAmount.currency.chainId)) { + return undefined + } return gasUseEstimateUSD === 0 ? '<$0.01' : formatNumber({ input: gasUseEstimateUSD, type: NumberType.FiatGasPrice }) } @@ -36,7 +38,7 @@ function PriceImpactRow({ trade }: { trade: ClassicTrade }) { return ( - Price Impact +
{formatPercent(trade.priceImpact)}
@@ -69,12 +71,9 @@ export function SwapRoute({ trade }: { trade: ClassicTrade }) { - {Boolean(gasPrice) && Best price route costs ~{{ gasPrice }} in gas. } + {Boolean(gasPrice) && } {Boolean(gasPrice) && ' '} - - This route optimizes your total output by considering split routes, multiple hops, and the gas cost of each - step. - + ) : ( diff --git a/apps/web/src/components/swap/SwapSkeleton.tsx b/apps/web/src/components/swap/SwapSkeleton.tsx index 0b2134297dc..8f413f70ff5 100644 --- a/apps/web/src/components/swap/SwapSkeleton.tsx +++ b/apps/web/src/components/swap/SwapSkeleton.tsx @@ -64,7 +64,7 @@ function Title() { return ( - Swap + ) diff --git a/apps/web/src/components/swap/UnsupportedCurrencyFooter.tsx b/apps/web/src/components/swap/UnsupportedCurrencyFooter.tsx index b686add7b4d..334f7c68f5e 100644 --- a/apps/web/src/components/swap/UnsupportedCurrencyFooter.tsx +++ b/apps/web/src/components/swap/UnsupportedCurrencyFooter.tsx @@ -6,6 +6,7 @@ import CurrencyLogo from 'components/Logo/CurrencyLogo' import Modal from 'components/Modal' import { AutoRow, RowBetween } from 'components/Row' import { useCurrencyInfo } from 'hooks/Tokens' +import { useAccount } from 'hooks/useAccount' import { Trans } from 'i18n' import { useState } from 'react' import styled from 'styled-components' @@ -13,7 +14,6 @@ import { CloseIcon, ExternalLink, ThemedText } from 'theme/components' import { Z_INDEX } from 'theme/zIndex' import { Text } from 'ui/src' import { SafetyLevel } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' -import { useChainId } from 'wagmi' import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink' @@ -56,7 +56,7 @@ export default function UnsupportedCurrencyFooter({ show: boolean currencies: (Currency | undefined | null)[] }) { - const chainId = useChainId() + const { chainId } = useAccount() const [showDetails, setShowDetails] = useState(false) const tokens = @@ -73,7 +73,7 @@ export default function UnsupportedCurrencyFooter({ - Unsupported assets + setShowDetails(false)} data-testid="close-icon" /> @@ -84,10 +84,7 @@ export default function UnsupportedCurrencyFooter({ })} - - Some assets are not available through this interface because they may not work well with the smart - contracts or we are unable to allow trading for legal reasons. - + @@ -95,7 +92,7 @@ export default function UnsupportedCurrencyFooter({ setShowDetails(true)} data-testid="read-more-button"> - Read more about unsupported assets + diff --git a/apps/web/src/components/swap/constants.ts b/apps/web/src/components/swap/constants.ts index 790917e3700..3f7283fd532 100644 --- a/apps/web/src/components/swap/constants.ts +++ b/apps/web/src/components/swap/constants.ts @@ -4,12 +4,6 @@ import { LDO, MNW, NMR, USDT as USDT_MAINNET } from 'constants/tokens' // See the `approve` function here: https://etherscan.io/address/0xdAC17F958D2ee523a2206206994597C13D831ec7#code export const RESET_APPROVAL_TOKENS = [USDT_MAINNET, LDO, NMR, MNW] -export enum SwapTab { - Swap = 'swap', - Limit = 'limit', - Send = 'send', -} - export enum Field { INPUT = 'INPUT', OUTPUT = 'OUTPUT', diff --git a/apps/web/src/components/vote/DelegateModal.tsx b/apps/web/src/components/vote/DelegateModal.tsx index b87e3d28e84..ca20ff8d05b 100644 --- a/apps/web/src/components/vote/DelegateModal.tsx +++ b/apps/web/src/components/vote/DelegateModal.tsx @@ -77,7 +77,9 @@ export default function DelegateModal({ isOpen, onDismiss, title }: VoteModalPro setAttempting(true) // if callback not returned properly ignore - if (!delegateCallback) return + if (!delegateCallback) { + return + } // try delegation and store hash const hash = await delegateCallback(parsedAddress ?? undefined)?.catch((error) => { @@ -100,20 +102,20 @@ export default function DelegateModal({ isOpen, onDismiss, title }: VoteModalPro - Earned UNI tokens represent voting shares in Uniswap governance. + - You can either vote on each proposal yourself or delegate your votes to a third party. + {usingDelegate && } - {usingDelegate ? Delegate votes : Self-delegate} + {usingDelegate ? : } setUsingDelegate(!usingDelegate)}> - {usingDelegate ? Remove delegate : Add delegate +} + {usingDelegate ? : } @@ -123,7 +125,7 @@ export default function DelegateModal({ isOpen, onDismiss, title }: VoteModalPro - {usingDelegate ? Delegating votes : Unlocking votes} + {usingDelegate ? : } {formatCurrencyAmount(uniBalance, 4)} @@ -133,7 +135,7 @@ export default function DelegateModal({ isOpen, onDismiss, title }: VoteModalPro - Transaction submitted + {formatCurrencyAmount(uniBalance, 4)} diff --git a/apps/web/src/components/vote/ExecuteModal.tsx b/apps/web/src/components/vote/ExecuteModal.tsx index 25ac2a05b80..64f0400453e 100644 --- a/apps/web/src/components/vote/ExecuteModal.tsx +++ b/apps/web/src/components/vote/ExecuteModal.tsx @@ -1,9 +1,9 @@ +import { useAccount } from 'hooks/useAccount' import { Trans } from 'i18n' import { useState } from 'react' import { ArrowUpCircle, X } from 'react-feather' import styled, { useTheme } from 'styled-components' import { CustomLightSpinner, ExternalLink, ThemedText } from 'theme/components' -import { useChainId } from 'wagmi' import Circle from '../../assets/images/blue-loader.svg' import { useExecuteCallback } from '../../state/governance/hooks' @@ -40,7 +40,7 @@ interface ExecuteModalProps { } export default function ExecuteModal({ isOpen, onDismiss, proposalId }: ExecuteModalProps) { - const chainId = useChainId() + const { chainId } = useAccount() const executeCallback = useExecuteCallback() // monitor call to help UI loading state @@ -61,7 +61,9 @@ export default function ExecuteModal({ isOpen, onDismiss, proposalId }: ExecuteM setAttempting(true) // if callback not returned properly ignore - if (!executeCallback) return + if (!executeCallback) { + return + } // try delegation and store hash const hash = await executeCallback(proposalId)?.catch((error) => { @@ -81,18 +83,18 @@ export default function ExecuteModal({ isOpen, onDismiss, proposalId }: ExecuteM - Execute proposal {{ proposalId }} + - Executing this proposal will enact the calldata on-chain. + - Execute + @@ -110,11 +112,11 @@ export default function ExecuteModal({ isOpen, onDismiss, proposalId }: ExecuteM - Executing + - Confirm this transaction in your wallet + @@ -131,7 +133,7 @@ export default function ExecuteModal({ isOpen, onDismiss, proposalId }: ExecuteM - Execution submitted + {chainId && ( @@ -140,7 +142,7 @@ export default function ExecuteModal({ isOpen, onDismiss, proposalId }: ExecuteM style={{ marginLeft: '4px' }} > - View transaction on Explorer + )} diff --git a/apps/web/src/components/vote/ProposalEmptyState.tsx b/apps/web/src/components/vote/ProposalEmptyState.tsx index 611f74b4087..1c2048daa8e 100644 --- a/apps/web/src/components/vote/ProposalEmptyState.tsx +++ b/apps/web/src/components/vote/ProposalEmptyState.tsx @@ -1,8 +1,8 @@ import { ChainId } from '@uniswap/sdk-core' +import { useAccount } from 'hooks/useAccount' import { Trans } from 'i18n' import styled from 'styled-components' import { ThemedText } from 'theme/components' -import { useChainId } from 'wagmi' const EmptyProposals = styled.div` border: 1px solid ${({ theme }) => theme.neutral2}; @@ -37,24 +37,19 @@ const EmptyState = ({ HeaderContent, SubHeaderContent }: EmptyStateProps) => ( ) export default function ProposalEmptyState() { - const chainId = useChainId() + const { chainId } = useAccount() if (chainId && chainId !== ChainId.MAINNET) { return ( Please connect to Layer 1 Ethereum} - SubHeaderContent={() => ( - - Uniswap governance is only available on Layer 1. Switch your network to Ethereum Mainnet to view Proposals - and Vote. - - )} + HeaderContent={() => } + SubHeaderContent={() => } /> ) } return ( No proposals found.} - SubHeaderContent={() => Proposals submitted by community members will appear here.} + HeaderContent={() => } + SubHeaderContent={() => } /> ) } diff --git a/apps/web/src/components/vote/QueueModal.tsx b/apps/web/src/components/vote/QueueModal.tsx index 0d2b01e095d..08a4b826ff0 100644 --- a/apps/web/src/components/vote/QueueModal.tsx +++ b/apps/web/src/components/vote/QueueModal.tsx @@ -3,8 +3,8 @@ import { useState } from 'react' import { ArrowUpCircle, X } from 'react-feather' import styled, { useTheme } from 'styled-components' import { CustomLightSpinner, ExternalLink, ThemedText } from 'theme/components' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import Circle from '../../assets/images/blue-loader.svg' import { useQueueCallback } from '../../state/governance/hooks' import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink' @@ -40,7 +40,7 @@ interface QueueModalProps { } export default function QueueModal({ isOpen, onDismiss, proposalId }: QueueModalProps) { - const chainId = useChainId() + const { chainId } = useAccount() const queueCallback = useQueueCallback() // monitor call to help UI loading state @@ -61,7 +61,9 @@ export default function QueueModal({ isOpen, onDismiss, proposalId }: QueueModal setAttempting(true) // if callback not returned properly ignore - if (!queueCallback) return + if (!queueCallback) { + return + } // try delegation and store hash const hash = await queueCallback(proposalId)?.catch((error) => { @@ -81,18 +83,18 @@ export default function QueueModal({ isOpen, onDismiss, proposalId }: QueueModal - Queue proposal {{ proposalId }} + - Adding this proposal to the queue will allow it to be executed, after a delay. + - Queue + @@ -110,11 +112,11 @@ export default function QueueModal({ isOpen, onDismiss, proposalId }: QueueModal - Queueing + - Confirm this transaction in your wallet + @@ -131,7 +133,7 @@ export default function QueueModal({ isOpen, onDismiss, proposalId }: QueueModal - Transaction submitted + {chainId && ( @@ -140,7 +142,7 @@ export default function QueueModal({ isOpen, onDismiss, proposalId }: QueueModal style={{ marginLeft: '4px' }} > - View transaction on Explorer + )} diff --git a/apps/web/src/components/vote/VoteModal.tsx b/apps/web/src/components/vote/VoteModal.tsx index f13d10f7b25..e7b17518e31 100644 --- a/apps/web/src/components/vote/VoteModal.tsx +++ b/apps/web/src/components/vote/VoteModal.tsx @@ -4,8 +4,8 @@ import { ArrowUpCircle, X } from 'react-feather' import styled, { useTheme } from 'styled-components' import { CustomLightSpinner, ExternalLink, ThemedText } from 'theme/components' import { formatCurrencyAmount } from 'utils/formatCurrencyAmount' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import Circle from '../../assets/images/blue-loader.svg' import { useUserVotes, useVoteCallback } from '../../state/governance/hooks' import { VoteOption } from '../../state/governance/types' @@ -43,7 +43,7 @@ interface VoteModalProps { } export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }: VoteModalProps) { - const chainId = useChainId() + const { chainId } = useAccount() const voteCallback = useVoteCallback() const { votes: availableVotes } = useUserVotes() @@ -65,7 +65,9 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }: setAttempting(true) // if callback not returned properly ignore - if (!voteCallback || voteOption === undefined) return + if (!voteCallback || voteOption === undefined) { + return + } // try delegation and store hash const hash = await voteCallback(proposalId, voteOption)?.catch((error) => { @@ -86,26 +88,26 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }: {voteOption === VoteOption.Against ? ( - Vote against proposal {{ proposalId }} + ) : voteOption === VoteOption.For ? ( - Vote for proposal {{ proposalId }} + ) : ( - Vote to abstain on proposal {{ proposalId }} + )} - {{ amt: formatCurrencyAmount(availableVotes, 4) }} Votes + {voteOption === VoteOption.Against ? ( - Vote against proposal {{ proposalId }} + ) : voteOption === VoteOption.For ? ( - Vote for proposal {{ proposalId }} + ) : ( - Vote to abstain on proposal {{ proposalId }} + )} @@ -124,11 +126,11 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }: - Submitting vote + - Confirm this transaction in your wallet + @@ -145,7 +147,7 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }: - Transaction Submitted + {chainId && ( @@ -154,7 +156,7 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }: style={{ marginLeft: '4px' }} > - View transaction on Explorer + )} diff --git a/apps/web/src/connection/activate.ts b/apps/web/src/connection/activate.ts index eb41f12c339..d742f778ce2 100644 --- a/apps/web/src/connection/activate.ts +++ b/apps/web/src/connection/activate.ts @@ -1,8 +1,8 @@ import { InterfaceEventName, WalletConnectionResult } from '@uniswap/analytics-events' -import { sendAnalyticsEvent } from 'analytics' import { useCallback } from 'react' import { useLocation } from 'react-router-dom' import { trace } from 'tracing/trace' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { getCurrentPageFromLocation } from 'utils/urlRoutes' import { UserRejectedRequestError } from 'viem' import { Connector, useConnect } from 'wagmi' diff --git a/apps/web/src/connection/web3reactShim.ts b/apps/web/src/connection/web3reactShim.ts index 7884ecd984f..50f51fc7049 100644 --- a/apps/web/src/connection/web3reactShim.ts +++ b/apps/web/src/connection/web3reactShim.ts @@ -1,20 +1,19 @@ +import { ChainId } from '@uniswap/sdk-core' +import { useAccount } from 'hooks/useAccount' import { useEthersProvider } from 'hooks/useEthersProvider' import { useMemo } from 'react' -import { useAccount, useChainId } from 'wagmi' // eslint-disable-next-line import/no-unused-modules -- shim is used via a build alias in craco.config.cjs export function useWeb3React() { - // When connected via an unsupported network chainId !== disconnectedChainId const { address, chainId } = useAccount() - const disconnectedChainId = useChainId() const provider = useEthersProvider({ chainId }) return useMemo( () => ({ account: address, - chainId: chainId ?? disconnectedChainId, + chainId: chainId ?? ChainId.MAINNET, provider, }), - [address, chainId, disconnectedChainId, provider] + [address, chainId, provider] ) } diff --git a/apps/web/src/constants/chains.test.ts b/apps/web/src/constants/chains.test.ts index b38674b3381..503851a4542 100644 --- a/apps/web/src/constants/chains.test.ts +++ b/apps/web/src/constants/chains.test.ts @@ -157,11 +157,19 @@ const GQL_TESTNET_CHAINS = [Chain.EthereumGoerli, Chain.EthereumSepolia] as cons const uxSupportedGQLChains = [...GQLMainnetChains, ...GQL_TESTNET_CHAINS] as const test.each(GQLMainnetChains)('GQL_MAINNET_CHAINS generates the correct chains', (chain: InterfaceGqlChain) => { + if (chain === Chain.Zora) { + // TODO: Remove when Zora chain is supported + return + } expect(GQL_MAINNET_CHAINS.includes(chain)).toBe(true) expect(GQL_MAINNET_CHAINS.length).toEqual(GQLMainnetChains.length) }) test.each(uxSupportedGQLChains)('UX_SUPPORTED_GQL_CHAINS generates the correct chains', (chain: InterfaceGqlChain) => { + if (chain === Chain.Zora) { + // TODO: Remove when Zora chain is supported + return + } expect(UX_SUPPORTED_GQL_CHAINS.includes(chain)).toBe(true) expect(UX_SUPPORTED_GQL_CHAINS.length).toEqual(uxSupportedGQLChains.length) }) @@ -209,6 +217,10 @@ const chainToChainId = { test.each(Object.keys(chainToChainId).map((key) => key as InterfaceGqlChain))( 'CHAIN_NAME_TO_CHAIN_ID generates the correct chains', (chain) => { + if (chain === Chain.Zora) { + // TODO: Remove when Zora chain is supported + return + } const chainId = CHAIN_NAME_TO_CHAIN_ID[chain] expect(chainId).toBe(chainToChainId[chain]) } diff --git a/apps/web/src/constants/chains.ts b/apps/web/src/constants/chains.ts index e7c56dfcd80..d6a7924063c 100644 --- a/apps/web/src/constants/chains.ts +++ b/apps/web/src/constants/chains.ts @@ -1,3 +1,4 @@ +/* eslint-disable rulesdir/no-undefined-or */ import { ChainId, Currency, CurrencyAmount, Token, V2_ROUTER_ADDRESSES } from '@uniswap/sdk-core' import { CUSD_CELO, @@ -30,7 +31,27 @@ import { useCallback, useMemo } from 'react' import { useParams } from 'react-router-dom' import { RetryOptions } from 'state/activity/polling/retry' import { darkTheme } from 'theme/colors' -import { Chain } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' +import { Chain as BackendChainId } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' +import { ElementName, ElementNameType } from 'uniswap/src/features/telemetry/constants' +import { Chain } from 'viem' +import { + Prettify, + arbitrum, + arbitrumGoerli, + avalanche, + base, + blast, + bsc, + celo, + celoAlfajores, + goerli, + mainnet, + optimism, + optimismGoerli, + polygon, + polygonMumbai, + sepolia, +} from 'wagmi/chains' export const AVERAGE_L1_BLOCK_TIME = ms(`12s`) export const DEFAULT_MS_BEFORE_WARNING = ms(`10m`) @@ -71,8 +92,6 @@ export const SUPPORTED_INTERFACE_CHAIN_IDS = [ ChainId.BLAST, ] as const -export type SupportedInterfaceChainId = (typeof SUPPORTED_INTERFACE_CHAIN_IDS)[number] - export function isSupportedChainId(chainId?: number | ChainId | null): chainId is SupportedInterfaceChainId { return !!chainId && SUPPORTED_INTERFACE_CHAIN_IDS.includes(chainId as SupportedInterfaceChainId) } @@ -114,37 +133,12 @@ export function useSupportedChainId(chainId?: number): SupportedInterfaceChainId return chainDisabled ? undefined : (chainId as SupportedInterfaceChainId) } -/** - * TODO(WEB-4058): Move this into the new upcoming chain config - * Can't move into the chain configs without the type becoming widened to just `string`, so keeping this list separate for now. - */ -const CHAIN_URL_PARAMS = [ - 'arbitrum_goerli', - 'arbitrum', - 'avalanche', - 'base', - 'blast', - 'bnb', - 'celo_alfajores', - 'celo', - 'ethereum', - 'goerli', - 'optimism_goerli', - 'optimism', - 'polygon_mumbai', - 'polygon', - 'sepolia', -] as const -export type ChainSlug = (typeof CHAIN_URL_PARAMS)[number] -export const isChainUrlParam = (str?: string): str is ChainSlug => !!str && CHAIN_URL_PARAMS.includes(str as ChainSlug) -export const getChainUrlParam = (str?: string): ChainSlug | undefined => (isChainUrlParam(str) ? str : undefined) - export enum NetworkLayer { L1, L2, } -export type InterfaceGqlChain = Exclude +export type InterfaceGqlChain = Exclude interface BackendChain { chain: InterfaceGqlChain @@ -155,175 +149,175 @@ interface BackendChain { /** * Set to true if the chain does not have a specific GQLChain. Eg: Optimism-Goerli. */ - isSecondaryChain?: true + isSecondaryChain: boolean /** * Used for spot token prices */ - nativeTokenBackendAddress?: string -} - -interface RPCUrls { - /** - * Public JSON-RPC endpoints. - * These are used if an integrator does not provide an endpoint, or if the endpoint does not work. - * - * ONLY ADD URLS WHICH ARE ON THE METAMASK "Safe" LIST: https://chainid.network/chains.json. - * You should select the first valid (not API-key guarded) URL from the list. - * You must also add it to our CSP: public/csp.json. - * - * MetaMask allows switching to any URL, but displays a warning if it is not on the "Safe" list: - * https://github.com/MetaMask/metamask-mobile/blob/bdb7f37c90e4fc923881a07fca38d4e77c73a579/app/core/RPCMethods/wallet_addEthereumChain.js#L228-L235 - */ - safe: string[] - /** - * Fallback JSON-RPC endpoints, taken from chainlist.org. - */ - fallback?: string[] - /** - * Application-specific JSON-RPC endpoints. - * These are URLs which may only be used by the interface, due to origin policies, &c. - */ - appOnly: string[] - infuraPrefix?: string + nativeTokenBackendAddress: string | undefined } // TODO: https://linear.app/uniswap/issue/WEB-4058/chain-info-using-wagmi-chain-interface // Add createChainInfo function that appropriately sets the default values for each chain -interface BaseChainInfo { - readonly id: SupportedInterfaceChainId - readonly name: string - readonly urlParam: ChainSlug - readonly blockWaitMsBeforeWarning?: number - // Average block times were pulled from https://dune.com/jacobdcastro/avg-block-times on 2024-03-14, - // and corroborated with that chain's documentation/explorer. - // Blocks per mainnet epoch is computed as `Math.floor(12s / AVG_BLOCK_TIME)` and hard-coded. - // Default is 1 - readonly blockPerMainnetEpochForChainId: number - readonly pendingTransactionsRetryOptions?: RetryOptions - readonly docs: string - readonly bridge?: string - readonly explorer: string - readonly infoLink: string - readonly label: string - // The label for this chain, derived from the MetaMask "Safe" list. - // This is only needed if the default label does not match MetaMask's. - readonly safeLabel?: string - readonly helpCenterUrl?: string - readonly nativeCurrency: { - name: string // e.g. 'Goerli ETH', - symbol: string // e.g. 'gorETH', - decimals: number // e.g. 18, +type ChainInfo = Prettify< + Chain & { + readonly id: ChainId + readonly interfaceName: string + readonly urlParam: string + // eslint-disable-next-line rulesdir/no-undefined-or + readonly blockWaitMsBeforeWarning: number | undefined + // Average block times were pulled from https://dune.com/jacobdcastro/avg-block-times on 2024-03-14, + // and corroborated with that chain's documentation/explorer. + // Blocks per mainnet epoch is computed as `Math.floor(12s / AVG_BLOCK_TIME)` and hard-coded. + // Default is 1 + readonly blockPerMainnetEpochForChainId: number + readonly pendingTransactionsRetryOptions: RetryOptions | undefined + readonly docs: string + readonly infoLink: string + readonly label: string + readonly elementName: ElementNameType + // The label for this chain, derived from the MetaMask "Safe" list. + // This is only needed if the default label does not match MetaMask's. + readonly helpCenterUrl: string | undefined + readonly color: string | undefined + readonly backgroundColor: string | undefined + readonly chainPriority: number // Higher priority chains show up first in the chain selector + readonly supportsClientSideRouting: boolean + readonly supportsGasEstimates: boolean + readonly backendChain: BackendChain + readonly subgraphUrl: string | undefined + // Stablecoin amounts used when calculating spot price for a given currency. + // The amount is large enough to filter low liquidity pairs. + readonly spotPriceStablecoinAmount: CurrencyAmount + readonly stablecoins: Token[] + readonly assetRepoNetworkName: string | undefined // Name used to index the network on this repo: https://github.com/Uniswap/assets/ + readonly infuraPrefix: string | undefined + readonly networkLayer: NetworkLayer + readonly bridge: string | undefined + readonly statusPage: string | undefined } - readonly color?: string - readonly backgroundColor?: string - readonly chainPriority: number // Higher priority chains show up first in the chain selector - readonly supportsClientSideRouting: boolean - readonly supportsGasEstimates?: true - readonly isTestnetChain?: true - readonly backendChain: BackendChain - readonly rpcUrls: RPCUrls - readonly subgraphUrl?: string - // Stablecoin amounts used when calculating spot price for a given currency. - // The amount is large enough to filter low liquidity pairs. - readonly spotPriceStablecoinAmount: CurrencyAmount - readonly stablecoins: Token[] - readonly assetRepoNetworkName?: string // Name used to index the network on this repo: https://github.com/Uniswap/assets/ -} - -interface L1ChainInfo extends BaseChainInfo { - readonly networkLayer: NetworkLayer.L1 -} - -export interface L2ChainInfo extends BaseChainInfo { - readonly networkLayer: NetworkLayer.L2 - readonly bridge: string - readonly statusPage?: string -} - -export type ChainInfo = BaseChainInfo & (L1ChainInfo | L2ChainInfo) -type ChainInfoMap = { readonly [chainId in SupportedInterfaceChainId]: ChainInfo } - -export const CHAIN_INFO: ChainInfoMap = { - [ChainId.MAINNET]: { - id: ChainId.MAINNET, - name: 'mainnet', - urlParam: 'ethereum', - blockPerMainnetEpochForChainId: 1, - networkLayer: NetworkLayer.L1, - docs: 'https://docs.uniswap.org/', - explorer: 'https://etherscan.io/', - infoLink: 'https://info.uniswap.org/#/', - label: 'Ethereum', - nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, - color: darkTheme.chain_1, - chainPriority: 0, - supportsClientSideRouting: true, - supportsGasEstimates: true, - backendChain: { - chain: Chain.Ethereum, - backendSupported: true, +> + +const MAINNET = { + ...mainnet, + id: ChainId.MAINNET, + interfaceName: 'mainnet', + urlParam: 'ethereum', + blockPerMainnetEpochForChainId: 1, + blockWaitMsBeforeWarning: undefined, + pendingTransactionsRetryOptions: undefined, + networkLayer: NetworkLayer.L1, + docs: 'https://docs.uniswap.org/', + infoLink: 'https://info.uniswap.org/#/', + label: 'Ethereum', + elementName: ElementName.ChainEthereum, + helpCenterUrl: undefined, + backgroundColor: undefined, + color: darkTheme.chain_1, + chainPriority: 0, + supportsClientSideRouting: true, + supportsGasEstimates: true, + backendChain: { + chain: BackendChainId.Ethereum, + backendSupported: true, + isSecondaryChain: false, + nativeTokenBackendAddress: undefined, + }, + rpcUrls: { + default: { + http: ['https://cloudflare-eth.com'], + }, + fallback: { + http: ['https://rpc.ankr.com/eth', 'https://eth-mainnet.public.blastapi.io'], }, - rpcUrls: { - safe: ['https://cloudflare-eth.com'], - fallback: ['https://rpc.ankr.com/eth', 'https://eth-mainnet.public.blastapi.io'], - appOnly: [`https://mainnet.infura.io/v3/${INFURA_KEY}`, QUICKNODE_MAINNET_RPC_URL], - infuraPrefix: 'mainnet', + appOnly: { + http: [`https://mainnet.infura.io/v3/${INFURA_KEY}`, QUICKNODE_MAINNET_RPC_URL], }, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3?source=uniswap', - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_MAINNET, 100_000e6), - stablecoins: [USDC_MAINNET, DAI, USDT], - assetRepoNetworkName: 'ethereum', }, - [ChainId.GOERLI]: { - id: ChainId.GOERLI, - name: 'goerli', - urlParam: 'goerli', - blockPerMainnetEpochForChainId: 1, - networkLayer: NetworkLayer.L1, - docs: 'https://docs.uniswap.org/', - explorer: 'https://goerli.etherscan.io/', - infoLink: 'https://info.uniswap.org/#/', - label: 'Görli', - nativeCurrency: { name: 'Görli Ether', symbol: 'görETH', decimals: 18 }, - color: darkTheme.chain_5, - chainPriority: 0, - supportsClientSideRouting: true, - isTestnetChain: true, - backendChain: { - chain: Chain.EthereumGoerli, - backendSupported: true, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3?source=uniswap', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_MAINNET, 100_000e6), + stablecoins: [USDC_MAINNET, DAI, USDT], + assetRepoNetworkName: 'ethereum', + infuraPrefix: 'mainnet', + bridge: undefined, + statusPage: undefined, +} as const satisfies ChainInfo + +const GOERLI = { + ...goerli, + id: ChainId.GOERLI, + interfaceName: 'goerli', + urlParam: 'goerli', + blockPerMainnetEpochForChainId: 1, + blockWaitMsBeforeWarning: undefined, + pendingTransactionsRetryOptions: undefined, + networkLayer: NetworkLayer.L1, + docs: 'https://docs.uniswap.org/', + infoLink: 'https://info.uniswap.org/#/', + label: 'Görli', + elementName: ElementName.ChainEthereumGoerli, + helpCenterUrl: undefined, + color: darkTheme.chain_5, + backgroundColor: undefined, + chainPriority: 0, + supportsClientSideRouting: true, + supportsGasEstimates: false, + backendChain: { + chain: BackendChainId.EthereumGoerli, + backendSupported: true, + isSecondaryChain: false, + nativeTokenBackendAddress: undefined, + }, + rpcUrls: { + default: { + http: ['https://rpc.goerli.mudit.blog/'], + }, + fallback: { + http: ['https://rpc.ankr.com/eth_goerli'], }, - rpcUrls: { - safe: ['https://rpc.goerli.mudit.blog/'], - fallback: ['https://rpc.ankr.com/eth_goerli'], - appOnly: [`https://goerli.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'goerli', + appOnly: { + http: [`https://goerli.infura.io/v3/${INFURA_KEY}`], }, - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_GOERLI, 10_000e6), - stablecoins: [USDC_GOERLI], }, - [ChainId.SEPOLIA]: { - id: ChainId.SEPOLIA, - name: 'sepolia', - urlParam: 'sepolia', - blockPerMainnetEpochForChainId: 1, - networkLayer: NetworkLayer.L1, - docs: 'https://docs.uniswap.org/', - explorer: 'https://sepolia.etherscan.io/', - infoLink: 'https://info.uniswap.org/#/', - label: 'Sepolia', - nativeCurrency: { name: 'Sepolia Ether', symbol: 'SepoliaETH', decimals: 18 }, - color: darkTheme.chain_5, - chainPriority: 0, - supportsClientSideRouting: true, - isTestnetChain: true, - backendChain: { - chain: Chain.EthereumSepolia, - backendSupported: true, + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_GOERLI, 10_000e6), + stablecoins: [USDC_GOERLI], + infuraPrefix: 'goerli', + subgraphUrl: undefined, + assetRepoNetworkName: undefined, + bridge: undefined, + statusPage: undefined, +} as const satisfies ChainInfo + +const SEPOLIA = { + ...sepolia, + id: ChainId.SEPOLIA, + interfaceName: 'sepolia', + urlParam: 'sepolia', + blockPerMainnetEpochForChainId: 1, + blockWaitMsBeforeWarning: undefined, + pendingTransactionsRetryOptions: undefined, + networkLayer: NetworkLayer.L1, + docs: 'https://docs.uniswap.org/', + infoLink: 'https://info.uniswap.org/#/', + helpCenterUrl: undefined, + label: 'Sepolia', + elementName: ElementName.ChainSepolia, + color: darkTheme.chain_5, + backgroundColor: undefined, + chainPriority: 0, + supportsClientSideRouting: true, + supportsGasEstimates: false, + backendChain: { + chain: BackendChainId.EthereumSepolia, + backendSupported: true, + isSecondaryChain: false, + nativeTokenBackendAddress: undefined, + }, + rpcUrls: { + default: { + http: ['https://rpc.sepolia.org/'], }, - rpcUrls: { - safe: ['https://rpc.sepolia.org/'], - fallback: [ + fallback: { + http: [ 'https://rpc.sepolia.org/', 'https://rpc2.sepolia.org/', 'https://rpc.sepolia.online/', @@ -331,433 +325,564 @@ export const CHAIN_INFO: ChainInfoMap = { 'https://rpc-sepolia.rockx.com/', 'https://rpc.bordel.wtf/sepolia', ], - appOnly: [`https://sepolia.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'sepolia', }, - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_SEPOLIA, 10_000e6), - stablecoins: [USDC_SEPOLIA], + appOnly: { http: [`https://sepolia.infura.io/v3/${INFURA_KEY}`] }, }, - [ChainId.OPTIMISM]: { - id: ChainId.OPTIMISM, - name: 'optimism', - urlParam: 'optimism', - blockPerMainnetEpochForChainId: 6, - networkLayer: NetworkLayer.L2, - blockWaitMsBeforeWarning: ms(`25m`), - pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, - bridge: 'https://app.optimism.io/bridge', - docs: 'https://optimism.io/', - explorer: 'https://optimistic.etherscan.io/', - infoLink: 'https://info.uniswap.org/#/optimism/', - label: 'Optimism', - statusPage: 'https://optimism.io/status', - helpCenterUrl: 'https://help.uniswap.org/en/collections/3137778-uniswap-on-optimistic-ethereum-oξ', - nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, - color: darkTheme.chain_10, - backgroundColor: darkTheme.chain_10_background, - chainPriority: 2, - supportsClientSideRouting: true, - supportsGasEstimates: true, - backendChain: { - chain: Chain.Optimism, - backendSupported: true, - }, - rpcUrls: { - safe: ['https://mainnet.optimism.io/'], - fallback: ['https://rpc.ankr.com/optimism'], - appOnly: [`https://optimism-mainnet.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'optimism-mainnet', - }, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/ianlapham/optimism-post-regenesis?source=uniswap', - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(DAI_OPTIMISM, 10_000e18), - stablecoins: [USDC_OPTIMISM, DAI_OPTIMISM], - assetRepoNetworkName: 'optimism', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_SEPOLIA, 10_000e6), + stablecoins: [USDC_SEPOLIA], + infuraPrefix: 'sepolia', + subgraphUrl: undefined, + assetRepoNetworkName: undefined, + bridge: undefined, + statusPage: undefined, +} as const satisfies ChainInfo + +const OPTIMISM = { + ...optimism, + id: ChainId.OPTIMISM, + interfaceName: 'optimism', + urlParam: 'optimism', + blockPerMainnetEpochForChainId: 6, + networkLayer: NetworkLayer.L2, + blockWaitMsBeforeWarning: ms(`25m`), + pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, + bridge: 'https://app.optimism.io/bridge', + docs: 'https://optimism.io/', + infoLink: 'https://info.uniswap.org/#/optimism/', + label: 'Optimism', + elementName: ElementName.ChainOptimism, + statusPage: 'https://optimism.io/status', + helpCenterUrl: 'https://help.uniswap.org/en/collections/3137778-uniswap-on-optimistic-ethereum-oξ', + color: darkTheme.chain_10, + backgroundColor: darkTheme.chain_10_background, + chainPriority: 2, + supportsClientSideRouting: true, + supportsGasEstimates: true, + backendChain: { + chain: BackendChainId.Optimism, + backendSupported: true, + isSecondaryChain: false, + nativeTokenBackendAddress: undefined, }, - [ChainId.OPTIMISM_GOERLI]: { - id: ChainId.OPTIMISM_GOERLI, - name: 'optimism_goerli', - urlParam: 'optimism_goerli', - blockPerMainnetEpochForChainId: 1, - networkLayer: NetworkLayer.L2, - blockWaitMsBeforeWarning: ms(`25m`), - pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, - bridge: 'https://app.optimism.io/bridge', - docs: 'https://optimism.io/', - explorer: 'https://goerli-optimism.etherscan.io/', - infoLink: 'https://info.uniswap.org/#/optimism/', - label: 'Optimism Görli', - statusPage: 'https://optimism.io/status', - helpCenterUrl: 'https://help.uniswap.org/en/collections/3137778-uniswap-on-optimistic-ethereum-oξ', - nativeCurrency: { name: 'Optimism Goerli Ether', symbol: 'görOpETH', decimals: 18 }, - color: darkTheme.chain_420, - chainPriority: 2, - supportsClientSideRouting: true, - isTestnetChain: true, - backendChain: { - chain: Chain.Optimism, - isSecondaryChain: true, - backendSupported: true, - }, - rpcUrls: { - safe: ['https://goerli.optimism.io'], - appOnly: [`https://optimism-goerli.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'optimism-goerli', - }, - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_OPTIMISM_GOERLI, 10_000e6), - stablecoins: [USDC_OPTIMISM_GOERLI], + rpcUrls: { + default: { http: ['https://mainnet.optimism.io/'] }, + fallback: { http: ['https://rpc.ankr.com/optimism'] }, + appOnly: { http: [`https://optimism-mainnet.infura.io/v3/${INFURA_KEY}`] }, }, - [ChainId.ARBITRUM_ONE]: { - id: ChainId.ARBITRUM_ONE, - name: 'arbitrum', - urlParam: 'arbitrum', - blockPerMainnetEpochForChainId: 46, - networkLayer: NetworkLayer.L2, - blockWaitMsBeforeWarning: ms(`10m`), - pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, - bridge: 'https://bridge.arbitrum.io/', - docs: 'https://offchainlabs.com/', - explorer: 'https://arbiscan.io/', - infoLink: 'https://info.uniswap.org/#/arbitrum', - label: 'Arbitrum', - helpCenterUrl: 'https://help.uniswap.org/en/collections/3137787-uniswap-on-arbitrum', - nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, - color: darkTheme.chain_42, - backgroundColor: darkTheme.chain_42161_background, - chainPriority: 1, - supportsClientSideRouting: true, - supportsGasEstimates: true, - backendChain: { - chain: Chain.Arbitrum, - backendSupported: true, - }, - rpcUrls: { - safe: ['https://arb1.arbitrum.io/rpc'], - fallback: ['https://arbitrum.public-rpc.com'], - appOnly: [`https://arbitrum-mainnet.infura.io/v3/${INFURA_KEY}`, QUICKNODE_ARBITRUM_RPC_URL], - infuraPrefix: 'arbitrum-mainnet', - }, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-arbitrum-one?source=uniswap', - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_ARBITRUM, 10_000e6), - stablecoins: [USDC_ARBITRUM, DAI_ARBITRUM_ONE], - assetRepoNetworkName: 'arbitrum', + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/ianlapham/optimism-post-regenesis?source=uniswap', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(DAI_OPTIMISM, 10_000e18), + stablecoins: [USDC_OPTIMISM, DAI_OPTIMISM], + assetRepoNetworkName: 'optimism', + infuraPrefix: 'optimism-mainnet', +} as const satisfies ChainInfo + +const OPTIMISM_GOERLI = { + ...optimismGoerli, + id: ChainId.OPTIMISM_GOERLI, + interfaceName: 'optimism_goerli', + urlParam: 'optimism_goerli', + blockPerMainnetEpochForChainId: 1, + networkLayer: NetworkLayer.L2, + blockWaitMsBeforeWarning: ms(`25m`), + pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, + bridge: 'https://app.optimism.io/bridge', + docs: 'https://optimism.io/', + infoLink: 'https://info.uniswap.org/#/optimism/', + label: 'Optimism Görli', + elementName: ElementName.ChainOptimismGoerli, + statusPage: 'https://optimism.io/status', + helpCenterUrl: 'https://help.uniswap.org/en/collections/3137778-uniswap-on-optimistic-ethereum-oξ', + color: darkTheme.chain_420, + backgroundColor: undefined, + chainPriority: 2, + supportsClientSideRouting: true, + supportsGasEstimates: false, + backendChain: { + chain: BackendChainId.Optimism, + isSecondaryChain: true, + backendSupported: true, + nativeTokenBackendAddress: undefined, }, - [ChainId.ARBITRUM_GOERLI]: { - id: ChainId.ARBITRUM_GOERLI, - name: 'arbitrum_goerli', - urlParam: 'arbitrum_goerli', - blockPerMainnetEpochForChainId: 1, - networkLayer: NetworkLayer.L2, - blockWaitMsBeforeWarning: ms(`10m`), - pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, - bridge: 'https://bridge.arbitrum.io/', - docs: 'https://offchainlabs.com/', - explorer: 'https://goerli.arbiscan.io/', - infoLink: 'https://info.uniswap.org/#/arbitrum/', - label: 'Arbitrum Goerli', - helpCenterUrl: 'https://help.uniswap.org/en/collections/3137787-uniswap-on-arbitrum', - nativeCurrency: { name: 'Goerli Arbitrum Ether', symbol: 'goerliArbETH', decimals: 18 }, - color: darkTheme.chain_421613, - chainPriority: 1, - supportsClientSideRouting: true, - isTestnetChain: true, - backendChain: { - chain: Chain.Arbitrum, - isSecondaryChain: true, - backendSupported: true, - }, - rpcUrls: { - safe: ['https://goerli-rollup.arbitrum.io/rpc'], - appOnly: [`https://arbitrum-goerli.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'arbitrum-goerli', - }, - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_ARBITRUM_GOERLI, 10_000e6), - stablecoins: [USDC_ARBITRUM_GOERLI], + rpcUrls: { + default: { http: ['https://goerli.optimism.io'] }, + appOnly: { http: [`https://optimism-goerli.infura.io/v3/${INFURA_KEY}`] }, }, - [ChainId.POLYGON]: { - id: ChainId.POLYGON, - name: 'polygon', - urlParam: 'polygon', - blockPerMainnetEpochForChainId: 5, - networkLayer: NetworkLayer.L1, - blockWaitMsBeforeWarning: ms(`10m`), - bridge: 'https://wallet.polygon.technology/polygon/bridge', - docs: 'https://polygon.io/', - explorer: 'https://polygonscan.com/', - infoLink: 'https://info.uniswap.org/#/polygon/', - label: 'Polygon', - safeLabel: 'Polygon Mainnet', - nativeCurrency: { name: 'Polygon Matic', symbol: 'MATIC', decimals: 18 }, - color: darkTheme.chain_137, - backgroundColor: darkTheme.chain_137_background, - chainPriority: 3, - supportsClientSideRouting: true, - supportsGasEstimates: true, - backendChain: { - chain: Chain.Polygon, - backendSupported: true, - nativeTokenBackendAddress: MATIC_POLYGON.address, - }, - rpcUrls: { - safe: ['https://polygon-rpc.com/'], - appOnly: [`https://polygon-mainnet.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'polygon-mainnet', - }, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-polygon?source=uniswap', - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_POLYGON, 10_000e6), - stablecoins: [USDC_POLYGON, DAI_POLYGON], - assetRepoNetworkName: 'polygon', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_OPTIMISM_GOERLI, 10_000e6), + stablecoins: [USDC_OPTIMISM_GOERLI], + infuraPrefix: 'optimism-goerli', + subgraphUrl: undefined, + assetRepoNetworkName: undefined, +} as const satisfies ChainInfo + +const ARBITRUM = { + ...arbitrum, + id: ChainId.ARBITRUM_ONE, + interfaceName: 'arbitrum', + urlParam: 'arbitrum', + blockPerMainnetEpochForChainId: 46, + networkLayer: NetworkLayer.L2, + blockWaitMsBeforeWarning: ms(`10m`), + pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, + bridge: 'https://bridge.arbitrum.io/', + docs: 'https://offchainlabs.com/', + infoLink: 'https://info.uniswap.org/#/arbitrum', + label: 'Arbitrum', + elementName: ElementName.ChainArbitrum, + helpCenterUrl: 'https://help.uniswap.org/en/collections/3137787-uniswap-on-arbitrum', + color: darkTheme.chain_42, + backgroundColor: darkTheme.chain_42161_background, + chainPriority: 1, + supportsClientSideRouting: true, + supportsGasEstimates: true, + backendChain: { + chain: BackendChainId.Arbitrum, + backendSupported: true, + isSecondaryChain: false, + nativeTokenBackendAddress: undefined, }, - [ChainId.POLYGON_MUMBAI]: { - id: ChainId.POLYGON_MUMBAI, - name: 'polygon_mumbai', - urlParam: 'polygon_mumbai', - blockPerMainnetEpochForChainId: 1, - networkLayer: NetworkLayer.L1, - blockWaitMsBeforeWarning: ms(`10m`), - bridge: 'https://wallet.polygon.technology/polygon/bridge/deposit', - docs: 'https://polygon.io/', - explorer: 'https://mumbai.polygonscan.com/', - infoLink: 'https://info.uniswap.org/#/polygon/', - label: 'Polygon Mumbai', - nativeCurrency: { name: 'Polygon Mumbai Matic', symbol: 'mMATIC', decimals: 18 }, - chainPriority: 3, - supportsClientSideRouting: true, - isTestnetChain: true, - backendChain: { - chain: Chain.Polygon, - isSecondaryChain: true, - backendSupported: true, - nativeTokenBackendAddress: MATIC_POLYGON.address, - }, - rpcUrls: { - safe: ['https://rpc-mumbai.maticvigil.com'], - appOnly: [`https://polygon-mumbai.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'polygon-mumbai', - }, - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_POLYGON_MUMBAI, 10_000e6), - stablecoins: [USDC_POLYGON_MUMBAI], + rpcUrls: { + default: { http: ['https://arb1.arbitrum.io/rpc'] }, + fallback: { http: ['https://arbitrum.public-rpc.com'] }, + appOnly: { http: [`https://arbitrum-mainnet.infura.io/v3/${INFURA_KEY}`, QUICKNODE_ARBITRUM_RPC_URL] }, }, - [ChainId.CELO]: { - id: ChainId.CELO, - name: 'celo', - urlParam: 'celo', - blockPerMainnetEpochForChainId: 2, - networkLayer: NetworkLayer.L1, - blockWaitMsBeforeWarning: ms(`10m`), - bridge: 'https://www.portalbridge.com/#/transfer', - docs: 'https://docs.celo.org/', - explorer: 'https://celoscan.io/', - infoLink: 'https://info.uniswap.org/#/celo/', - label: 'Celo', - safeLabel: 'Celo Mainnet', - nativeCurrency: { name: 'Celo', symbol: 'CELO', decimals: 18 }, - chainPriority: 7, - supportsClientSideRouting: true, - supportsGasEstimates: true, - backendChain: { - chain: Chain.Celo, - backendSupported: true, - nativeTokenBackendAddress: nativeOnChain(ChainId.CELO).wrapped.address, - }, - rpcUrls: { - safe: [`https://forno.celo.org`], - appOnly: [`https://celo-mainnet.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'celo-mainnet', - }, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/jesse-sawa/uniswap-celo?source=uniswap', - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(CUSD_CELO, 10_000e18), - stablecoins: [USDC_CELO], - assetRepoNetworkName: 'celo', + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-arbitrum-one?source=uniswap', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_ARBITRUM, 10_000e6), + stablecoins: [USDC_ARBITRUM, DAI_ARBITRUM_ONE], + assetRepoNetworkName: 'arbitrum', + infuraPrefix: 'arbitrum-mainnet', + statusPage: undefined, +} as const satisfies ChainInfo + +const ARBITRUM_GOERLI = { + ...arbitrumGoerli, + id: ChainId.ARBITRUM_GOERLI, + interfaceName: 'arbitrum_goerli', + urlParam: 'arbitrum_goerli', + blockPerMainnetEpochForChainId: 1, + networkLayer: NetworkLayer.L2, + blockWaitMsBeforeWarning: ms(`10m`), + pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, + bridge: 'https://bridge.arbitrum.io/', + docs: 'https://offchainlabs.com/', + infoLink: 'https://info.uniswap.org/#/arbitrum/', + label: 'Arbitrum Goerli', + elementName: ElementName.ChainArbitrumGoerli, + helpCenterUrl: 'https://help.uniswap.org/en/collections/3137787-uniswap-on-arbitrum', + color: darkTheme.chain_421613, + backgroundColor: undefined, + chainPriority: 1, + supportsClientSideRouting: true, + supportsGasEstimates: false, + backendChain: { + chain: BackendChainId.Arbitrum, + isSecondaryChain: true, + backendSupported: true, + nativeTokenBackendAddress: undefined, }, - [ChainId.CELO_ALFAJORES]: { - id: ChainId.CELO_ALFAJORES, - name: 'celo_alfajores', - urlParam: 'celo_alfajores', - blockPerMainnetEpochForChainId: 1, - networkLayer: NetworkLayer.L1, - blockWaitMsBeforeWarning: ms(`10m`), - bridge: 'https://www.portalbridge.com/#/transfer', - docs: 'https://docs.celo.org/', - explorer: 'https://alfajores-blockscout.celo-testnet.org/', - infoLink: 'https://info.uniswap.org/#/celo/', - label: 'Celo Alfajores', - nativeCurrency: { name: 'Celo', symbol: 'CELO', decimals: 18 }, - chainPriority: 7, - supportsClientSideRouting: true, - isTestnetChain: true, - backendChain: { - chain: Chain.Celo, - isSecondaryChain: true, - backendSupported: true, - nativeTokenBackendAddress: nativeOnChain(ChainId.CELO_ALFAJORES).wrapped.address, - }, - rpcUrls: { - safe: [`https://alfajores-forno.celo-testnet.org`], - appOnly: [`https://celo-alfajores.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'celo-alfajores', - }, - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(CUSD_CELO_ALFAJORES, 10_000e6), - stablecoins: [USDC_CELO], + rpcUrls: { + default: { http: ['https://goerli-rollup.arbitrum.io/rpc'] }, + appOnly: { http: [`https://arbitrum-goerli.infura.io/v3/${INFURA_KEY}`] }, }, - [ChainId.BNB]: { - id: ChainId.BNB, - name: 'bnb', - urlParam: 'bnb', - blockPerMainnetEpochForChainId: 4, - networkLayer: NetworkLayer.L1, - blockWaitMsBeforeWarning: ms(`10m`), - bridge: 'https://cbridge.celer.network/1/56', - docs: 'https://docs.bnbchain.org/', - explorer: 'https://bscscan.com/', - infoLink: 'https://info.uniswap.org/#/bnb/', - label: 'BNB Chain', - safeLabel: 'BNB Smart Chain Mainnet', - nativeCurrency: { name: 'BNB', symbol: 'BNB', decimals: 18 }, - color: darkTheme.chain_56, - backgroundColor: darkTheme.chain_56_background, - chainPriority: 5, - supportsClientSideRouting: true, - supportsGasEstimates: true, - backendChain: { - chain: Chain.Bnb, - backendSupported: true, - }, - rpcUrls: { - safe: ['https://bsc-dataseed1.bnbchain.org'], - appOnly: [QUICKNODE_BNB_RPC_URL], - }, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-bsc?source=uniswap', - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDT_BSC, 100e18), - stablecoins: [USDC_BSC], - assetRepoNetworkName: 'smartchain', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_ARBITRUM_GOERLI, 10_000e6), + stablecoins: [USDC_ARBITRUM_GOERLI], + infuraPrefix: 'arbitrum-goerli', + subgraphUrl: undefined, + assetRepoNetworkName: undefined, + statusPage: undefined, +} as const satisfies ChainInfo + +const POLYGON = { + ...polygon, + id: ChainId.POLYGON, + name: 'Polygon Mainnet', + interfaceName: 'polygon', + urlParam: 'polygon', + blockPerMainnetEpochForChainId: 5, + networkLayer: NetworkLayer.L1, + blockWaitMsBeforeWarning: ms(`10m`), + pendingTransactionsRetryOptions: undefined, + bridge: 'https://wallet.polygon.technology/polygon/bridge', + docs: 'https://polygon.io/', + infoLink: 'https://info.uniswap.org/#/polygon/', + helpCenterUrl: undefined, + label: 'Polygon', + elementName: ElementName.ChainPolygon, + color: darkTheme.chain_137, + backgroundColor: darkTheme.chain_137_background, + chainPriority: 3, + supportsClientSideRouting: true, + supportsGasEstimates: true, + backendChain: { + chain: BackendChainId.Polygon, + backendSupported: true, + nativeTokenBackendAddress: MATIC_POLYGON.address, + isSecondaryChain: false, }, - [ChainId.AVALANCHE]: { - id: ChainId.AVALANCHE, - name: 'avalanche', - urlParam: 'avalanche', - blockPerMainnetEpochForChainId: 6, - networkLayer: NetworkLayer.L1, - blockWaitMsBeforeWarning: ms(`10m`), - bridge: 'https://core.app/bridge/', - docs: 'https://docs.avax.network/', - explorer: 'https://snowtrace.io/', - infoLink: 'https://info.uniswap.org/#/avax/', // TODO(WEB-2336): Add avax support to info site - label: 'Avalanche', - safeLabel: 'Avalanche C-Chain', - nativeCurrency: { name: 'AVAX', symbol: 'AVAX', decimals: 18 }, - color: darkTheme.chain_43114, - backgroundColor: darkTheme.chain_43114_background, - chainPriority: 6, - supportsClientSideRouting: true, - supportsGasEstimates: true, - backendChain: { - chain: Chain.Avalanche, - backendSupported: false, - }, - rpcUrls: { - safe: ['https://api.avax.network/ext/bc/C/rpc'], - appOnly: [`https://avalanche-mainnet.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'avalanche-mainnet', - }, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/lynnshaoyu/uniswap-v3-avax?source=uniswap', - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_AVALANCHE, 10_000e6), - stablecoins: [USDC_AVALANCHE], - assetRepoNetworkName: 'avalanchec', + rpcUrls: { + default: { http: ['https://polygon-rpc.com/'] }, + appOnly: { http: [`https://polygon-mainnet.infura.io/v3/${INFURA_KEY}`] }, }, - [ChainId.BASE]: { - id: ChainId.BASE, - name: 'base', - urlParam: 'base', - blockPerMainnetEpochForChainId: 6, - networkLayer: NetworkLayer.L2, - blockWaitMsBeforeWarning: ms(`25m`), - pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, - bridge: 'https://bridge.base.org/deposit', - docs: 'https://docs.base.org', - explorer: 'https://basescan.org/', - infoLink: 'https://info.uniswap.org/#/base/', - label: 'Base', - statusPage: 'https://status.base.org/', - nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, - color: darkTheme.chain_84531, - chainPriority: 4, - supportsClientSideRouting: true, - supportsGasEstimates: true, - backendChain: { - chain: Chain.Base, - backendSupported: true, - }, - rpcUrls: { - safe: ['https://mainnet.base.org/'], - fallback: ['https://1rpc.io/base', 'https://base.meowrpc.com'], - appOnly: [`https://base-mainnet.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'base-mainnet', - }, - subgraphUrl: 'https://api.studio.thegraph.com/query/48211/uniswap-v3-base/version/latest?source=uniswap', - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_BASE, 10_000e6), - assetRepoNetworkName: 'base', - stablecoins: [USDC_BASE], + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-polygon?source=uniswap', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_POLYGON, 10_000e6), + stablecoins: [USDC_POLYGON, DAI_POLYGON], + assetRepoNetworkName: 'polygon', + infuraPrefix: 'polygon-mainnet', + statusPage: undefined, +} as const satisfies ChainInfo + +const POLYGON_MUMBAI = { + ...polygonMumbai, + id: ChainId.POLYGON_MUMBAI, + interfaceName: 'polygon_mumbai', + urlParam: 'polygon_mumbai', + blockPerMainnetEpochForChainId: 1, + networkLayer: NetworkLayer.L1, + blockWaitMsBeforeWarning: ms(`10m`), + pendingTransactionsRetryOptions: undefined, + bridge: 'https://wallet.polygon.technology/polygon/bridge/deposit', + docs: 'https://polygon.io/', + infoLink: 'https://info.uniswap.org/#/polygon/', + helpCenterUrl: undefined, + label: 'Polygon Mumbai', + elementName: ElementName.ChainPolygonMumbai, + color: darkTheme.chain_137, + backgroundColor: darkTheme.chain_137_background, + chainPriority: 3, + supportsClientSideRouting: true, + supportsGasEstimates: false, + backendChain: { + chain: BackendChainId.Polygon, + isSecondaryChain: true, + backendSupported: true, + nativeTokenBackendAddress: MATIC_POLYGON.address, }, - [ChainId.BLAST]: { - id: ChainId.BLAST, - name: 'blast', - urlParam: 'blast', - blockPerMainnetEpochForChainId: 1, - networkLayer: NetworkLayer.L2, - pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, - bridge: 'https://blast.io/bridge', - docs: 'https://docs.blast.io', - explorer: 'https://blastscan.io/', - infoLink: 'https://info.uniswap.org/#/blast/', - label: 'Blast', - nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, - color: darkTheme.chain_81457, - chainPriority: 8, - supportsClientSideRouting: false, - supportsGasEstimates: true, - backendChain: { - chain: Chain.Blast, - backendSupported: true, - }, - rpcUrls: { - safe: ['https://rpc.blast.io/'], - appOnly: [`https://blast-mainnet.infura.io/v3/${INFURA_KEY}`], - infuraPrefix: 'blast-mainnet', - }, - subgraphUrl: - 'https://gateway-arbitrum.network.thegraph.com/api/0ae45f0bf40ae2e73119b44ccd755967/subgraphs/id/2LHovKznvo8YmKC9ZprPjsYAZDCc4K5q4AYz8s3cnQn1', - spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDB_BLAST, 10_000e18), - stablecoins: [USDB_BLAST], - assetRepoNetworkName: 'blast', + rpcUrls: { + default: { http: ['https://rpc-mumbai.maticvigil.com'] }, + appOnly: { http: [`https://polygon-mumbai.infura.io/v3/${INFURA_KEY}`] }, + }, + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_POLYGON_MUMBAI, 10_000e6), + stablecoins: [USDC_POLYGON_MUMBAI], + infuraPrefix: 'polygon-mumbai', + assetRepoNetworkName: undefined, + subgraphUrl: undefined, + statusPage: undefined, +} as const satisfies ChainInfo + +const CELO = { + ...celo, + id: ChainId.CELO, + name: 'Celo Mainnet', + interfaceName: 'celo', + urlParam: 'celo', + blockPerMainnetEpochForChainId: 2, + networkLayer: NetworkLayer.L1, + blockWaitMsBeforeWarning: ms(`10m`), + pendingTransactionsRetryOptions: undefined, + bridge: 'https://www.portalbridge.com/#/transfer', + docs: 'https://docs.celo.org/', + infoLink: 'https://info.uniswap.org/#/celo/', + helpCenterUrl: undefined, + label: 'Celo', + elementName: ElementName.ChainCelo, + chainPriority: 7, + color: undefined, + backgroundColor: undefined, + supportsClientSideRouting: true, + supportsGasEstimates: true, + backendChain: { + chain: BackendChainId.Celo, + backendSupported: true, + nativeTokenBackendAddress: nativeOnChain(ChainId.CELO).wrapped.address, + isSecondaryChain: false, + }, + rpcUrls: { + default: { http: [`https://forno.celo.org`] }, + appOnly: { http: [`https://celo-mainnet.infura.io/v3/${INFURA_KEY}`] }, }, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/jesse-sawa/uniswap-celo?source=uniswap', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(CUSD_CELO, 10_000e18), + stablecoins: [USDC_CELO], + assetRepoNetworkName: 'celo', + infuraPrefix: 'celo-mainnet', + statusPage: undefined, +} as const satisfies ChainInfo + +const CELO_ALFAJORES = { + ...celoAlfajores, + id: ChainId.CELO_ALFAJORES, + interfaceName: 'celo_alfajores', + urlParam: 'celo_alfajores', + blockPerMainnetEpochForChainId: 1, + networkLayer: NetworkLayer.L1, + blockWaitMsBeforeWarning: ms(`10m`), + pendingTransactionsRetryOptions: undefined, + bridge: 'https://www.portalbridge.com/#/transfer', + docs: 'https://docs.celo.org/', + infoLink: 'https://info.uniswap.org/#/celo/', + helpCenterUrl: undefined, + label: 'Celo Alfajores', + elementName: ElementName.ChainCeloAlfajores, + chainPriority: 7, + color: undefined, + backgroundColor: undefined, + supportsClientSideRouting: true, + supportsGasEstimates: false, + backendChain: { + chain: BackendChainId.Celo, + isSecondaryChain: true, + backendSupported: true, + nativeTokenBackendAddress: nativeOnChain(ChainId.CELO_ALFAJORES).wrapped.address, + }, + rpcUrls: { + default: { http: [`https://alfajores-forno.celo-testnet.org`] }, + appOnly: { http: [`https://celo-alfajores.infura.io/v3/${INFURA_KEY}`] }, + }, + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(CUSD_CELO_ALFAJORES, 10_000e6), + stablecoins: [USDC_CELO], + infuraPrefix: 'celo-alfajores', + assetRepoNetworkName: undefined, + subgraphUrl: undefined, + statusPage: undefined, +} as const satisfies ChainInfo + +const BNB = { + ...bsc, + id: ChainId.BNB, + name: 'BNB Smart Chain Mainnet', + interfaceName: 'bnb', + urlParam: 'bnb', + blockPerMainnetEpochForChainId: 4, + networkLayer: NetworkLayer.L1, + blockWaitMsBeforeWarning: ms(`10m`), + pendingTransactionsRetryOptions: undefined, + bridge: 'https://cbridge.celer.network/1/56', + docs: 'https://docs.bnbchain.org/', + infoLink: 'https://info.uniswap.org/#/bnb/', + label: 'BNB Chain', + elementName: ElementName.ChainBNB, + helpCenterUrl: undefined, + color: darkTheme.chain_56, + backgroundColor: darkTheme.chain_56_background, + chainPriority: 5, + supportsClientSideRouting: true, + supportsGasEstimates: true, + backendChain: { + chain: BackendChainId.Bnb, + backendSupported: true, + isSecondaryChain: false, + nativeTokenBackendAddress: undefined, + }, + rpcUrls: { + default: { http: ['https://bsc-dataseed1.bnbchain.org'] }, + appOnly: { http: [QUICKNODE_BNB_RPC_URL] }, + }, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-bsc?source=uniswap', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDT_BSC, 100e18), + stablecoins: [USDC_BSC], + assetRepoNetworkName: 'smartchain', + infuraPrefix: undefined, + statusPage: undefined, +} as const satisfies ChainInfo + +const AVALANCHE = { + ...avalanche, + id: ChainId.AVALANCHE, + name: 'Avalanche C-Chain', + interfaceName: 'avalanche', + urlParam: 'avalanche', + blockPerMainnetEpochForChainId: 6, + networkLayer: NetworkLayer.L1, + blockWaitMsBeforeWarning: ms(`10m`), + pendingTransactionsRetryOptions: undefined, + bridge: 'https://core.app/bridge/', + docs: 'https://docs.avax.network/', + infoLink: 'https://info.uniswap.org/#/avax/', // TODO(WEB-2336): Add avax support to info site + helpCenterUrl: undefined, + label: 'Avalanche', + elementName: ElementName.ChainAvalanche, + nativeCurrency: { name: 'AVAX', symbol: 'AVAX', decimals: 18 }, + color: darkTheme.chain_43114, + backgroundColor: darkTheme.chain_43114_background, + chainPriority: 6, + supportsClientSideRouting: true, + supportsGasEstimates: true, + backendChain: { + chain: BackendChainId.Avalanche, + backendSupported: false, + isSecondaryChain: false, + nativeTokenBackendAddress: undefined, + }, + rpcUrls: { + default: { http: ['https://api.avax.network/ext/bc/C/rpc'] }, + appOnly: { http: [`https://avalanche-mainnet.infura.io/v3/${INFURA_KEY}`] }, + }, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/lynnshaoyu/uniswap-v3-avax?source=uniswap', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_AVALANCHE, 10_000e6), + stablecoins: [USDC_AVALANCHE], + assetRepoNetworkName: 'avalanchec', + infuraPrefix: 'avalanche-mainnet', + statusPage: undefined, +} as const satisfies ChainInfo + +const BASE = { + ...base, + id: ChainId.BASE, + interfaceName: 'base', + urlParam: 'base', + blockPerMainnetEpochForChainId: 6, + networkLayer: NetworkLayer.L2, + blockWaitMsBeforeWarning: ms(`25m`), + pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, + bridge: 'https://bridge.base.org/deposit', + docs: 'https://docs.base.org', + infoLink: 'https://info.uniswap.org/#/base/', + helpCenterUrl: undefined, + label: 'Base', + elementName: ElementName.ChainBase, + statusPage: 'https://status.base.org/', + nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, + color: darkTheme.chain_84531, + backgroundColor: undefined, + chainPriority: 4, + supportsClientSideRouting: true, + supportsGasEstimates: true, + backendChain: { + chain: BackendChainId.Base, + backendSupported: true, + isSecondaryChain: false, + nativeTokenBackendAddress: undefined, + }, + rpcUrls: { + default: { http: ['https://mainnet.base.org/'] }, + fallback: { http: ['https://1rpc.io/base', 'https://base.meowrpc.com'] }, + appOnly: { http: [`https://base-mainnet.infura.io/v3/${INFURA_KEY}`] }, + }, + subgraphUrl: 'https://api.studio.thegraph.com/query/48211/uniswap-v3-base/version/latest?source=uniswap', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDC_BASE, 10_000e6), + assetRepoNetworkName: 'base', + stablecoins: [USDC_BASE], + infuraPrefix: 'base-mainnet', +} as const satisfies ChainInfo + +const BLAST = { + ...blast, + id: ChainId.BLAST, + interfaceName: 'blast', + urlParam: 'blast', + blockPerMainnetEpochForChainId: 1, + networkLayer: NetworkLayer.L2, + pendingTransactionsRetryOptions: DEFAULT_RETRY_OPTIONS, + blockWaitMsBeforeWarning: undefined, + bridge: 'https://blast.io/bridge', + docs: 'https://docs.blast.io', + infoLink: 'https://info.uniswap.org/#/blast/', + helpCenterUrl: undefined, + label: 'Blast', + elementName: ElementName.ChainBlast, + nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, + color: darkTheme.chain_81457, + backgroundColor: undefined, + chainPriority: 8, + supportsClientSideRouting: false, + supportsGasEstimates: true, + backendChain: { + chain: BackendChainId.Blast, + backendSupported: true, + isSecondaryChain: false, + nativeTokenBackendAddress: undefined, + }, + rpcUrls: { + default: { http: ['https://rpc.blast.io/'] }, + appOnly: { http: [`https://blast-mainnet.infura.io/v3/${INFURA_KEY}`] }, + }, + subgraphUrl: + 'https://gateway-arbitrum.network.thegraph.com/api/0ae45f0bf40ae2e73119b44ccd755967/subgraphs/id/2LHovKznvo8YmKC9ZprPjsYAZDCc4K5q4AYz8s3cnQn1', + spotPriceStablecoinAmount: CurrencyAmount.fromRawAmount(USDB_BLAST, 10_000e18), + stablecoins: [USDB_BLAST], + assetRepoNetworkName: 'blast', + infuraPrefix: 'blast-mainnet', + statusPage: undefined, +} as const satisfies ChainInfo + +const INTERFACE_SUPPORTED_CHAINS = [ + MAINNET, + GOERLI, + SEPOLIA, + OPTIMISM, + OPTIMISM_GOERLI, + ARBITRUM, + ARBITRUM_GOERLI, + POLYGON, + POLYGON_MUMBAI, + AVALANCHE, + CELO, + CELO_ALFAJORES, + BNB, + BASE, + BLAST, +] as const + +type ExtractObject, TNarrowedObject extends Partial> = Extract< + TObject, + TNarrowedObject +> +export type SupportedInterfaceChain< + partialChain extends Partial<(typeof INTERFACE_SUPPORTED_CHAINS)[number]> = Partial< + (typeof INTERFACE_SUPPORTED_CHAINS)[number] + > +> = ExtractObject<(typeof INTERFACE_SUPPORTED_CHAINS)[number], partialChain> +export type SupportedInterfaceChainId = SupportedInterfaceChain['id'] +type ChainInfoMap = { readonly [chainId in SupportedInterfaceChainId]: SupportedInterfaceChain } + +export const CHAIN_INFO: ChainInfoMap = { + [ChainId.MAINNET]: MAINNET, + [ChainId.GOERLI]: GOERLI, + [ChainId.SEPOLIA]: SEPOLIA, + [ChainId.OPTIMISM]: OPTIMISM, + [ChainId.OPTIMISM_GOERLI]: OPTIMISM_GOERLI, + [ChainId.ARBITRUM_ONE]: ARBITRUM, + [ChainId.ARBITRUM_GOERLI]: ARBITRUM_GOERLI, + [ChainId.POLYGON]: POLYGON, + [ChainId.POLYGON_MUMBAI]: POLYGON_MUMBAI, + [ChainId.CELO]: CELO, + [ChainId.CELO_ALFAJORES]: CELO_ALFAJORES, + [ChainId.BNB]: BNB, + [ChainId.AVALANCHE]: AVALANCHE, + [ChainId.BASE]: BASE, + [ChainId.BLAST]: BLAST, } as const -export function getChainInfo(options: { chainId: SupportedInterfaceChainId }): ChainInfo -export function getChainInfo(options: { chainId?: SupportedInterfaceChainId; withFallback: true }): ChainInfo -export function getChainInfo(options: { +export type ChainSlug = SupportedInterfaceChain['urlParam'] +export const isChainUrlParam = (str?: string): str is ChainSlug => + !!str && Object.values(CHAIN_INFO).some((chain) => chain.urlParam === str) +export const getChainUrlParam = (str?: string): ChainSlug | undefined => (isChainUrlParam(str) ? str : undefined) + +export function getChain(options: { chainId: SupportedInterfaceChainId }): SupportedInterfaceChain +export function getChain(options: { chainId?: SupportedInterfaceChainId; withFallback: true }): SupportedInterfaceChain +export function getChain(options: { chainId?: SupportedInterfaceChainId withFallback?: boolean -}): ChainInfo | undefined -export function getChainInfo({ +}): SupportedInterfaceChain | undefined +export function getChain({ chainId, withFallback, }: { chainId?: SupportedInterfaceChainId withFallback?: boolean -}): ChainInfo | undefined { +}): SupportedInterfaceChain | undefined { return chainId ? CHAIN_INFO[chainId] : withFallback ? CHAIN_INFO[ChainId.MAINNET] : undefined } export const CHAIN_IDS_TO_NAMES = Object.fromEntries( - Object.entries(CHAIN_INFO).map(([key, value]) => [key, value.name]) + Object.entries(CHAIN_INFO).map(([key, value]) => [key, value.interfaceName]) ) as { [chainId in SupportedInterfaceChainId]: string } export const GQL_MAINNET_CHAINS = Object.values(CHAIN_INFO) - .filter((chain) => !chain.isTestnetChain && !chain.backendChain.isSecondaryChain) + .filter((chain) => !chain.testnet && !chain.backendChain.isSecondaryChain) .map((chain) => chain.backendChain.chain) const GQL_TESTNET_CHAINS = Object.values(CHAIN_INFO) - .filter((chain) => chain.isTestnetChain && !chain.backendChain.isSecondaryChain) + .filter((chain) => chain.testnet && !chain.backendChain.isSecondaryChain) .map((chain) => chain.backendChain.chain) export const UX_SUPPORTED_GQL_CHAINS = [...GQL_MAINNET_CHAINS, ...GQL_TESTNET_CHAINS] @@ -800,7 +925,7 @@ export const SUPPORTED_GAS_ESTIMATE_CHAIN_IDS = Object.keys(CHAIN_INFO) .map((key) => parseInt(key) as SupportedInterfaceChainId) export const TESTNET_CHAIN_IDS = Object.keys(CHAIN_INFO) - .filter((key) => CHAIN_INFO[parseInt(key) as SupportedInterfaceChainId].isTestnetChain) + .filter((key) => CHAIN_INFO[parseInt(key) as SupportedInterfaceChainId].testnet) .map((key) => parseInt(key) as SupportedInterfaceChainId) /** @@ -823,7 +948,6 @@ export type SupportedL2ChainId = (typeof L2_CHAIN_IDS)[number] /** * @deprecated when v2 pools are enabled on chains supported through sdk-core */ -export const SUPPORTED_V2POOL_CHAIN_IDS_DEPRECATED = [ChainId.MAINNET, ChainId.GOERLI] as const export const SUPPORTED_V2POOL_CHAIN_IDS = Object.keys(V2_ROUTER_ADDRESSES).map((chainId) => parseInt(chainId)) export const BACKEND_SUPPORTED_CHAINS = Object.keys(CHAIN_INFO) @@ -832,7 +956,7 @@ export const BACKEND_SUPPORTED_CHAINS = Object.keys(CHAIN_INFO) return ( CHAIN_INFO[chainId].backendChain.backendSupported && !CHAIN_INFO[chainId].backendChain.isSecondaryChain && - !CHAIN_INFO[chainId].isTestnetChain + !CHAIN_INFO[chainId].testnet ) }) .map((key) => CHAIN_INFO[parseInt(key) as SupportedInterfaceChainId].backendChain.chain as InterfaceGqlChain) @@ -843,8 +967,8 @@ export const BACKEND_NOT_YET_SUPPORTED_CHAIN_IDS = GQL_MAINNET_CHAINS.filter( export const INFURA_PREFIX_TO_CHAIN_ID: { [prefix: string]: SupportedInterfaceChainId } = Object.fromEntries( Object.entries(CHAIN_INFO) - .filter(([, value]) => !!value.rpcUrls.infuraPrefix) - .map(([key, value]) => [value.rpcUrls.infuraPrefix, parseInt(key) as SupportedInterfaceChainId]) + .filter(([, value]) => !!value.infuraPrefix) + .map(([key, value]) => [value.infuraPrefix, parseInt(key) as SupportedInterfaceChainId]) ) export const CHAIN_SUBGRAPH_URL = Object.fromEntries( @@ -871,19 +995,24 @@ export function isUniswapXSupportedChain(chainId?: number) { } export function isStablecoin(currency?: Currency): boolean { - if (!currency) return false + if (!currency) { + return false + } - return getChainInfo({ chainId: currency.chainId as SupportedInterfaceChainId }).stablecoins.some((stablecoin) => + return getChain({ chainId: currency.chainId as SupportedInterfaceChainId }).stablecoins.some((stablecoin) => stablecoin.equals(currency) ) } -export function getChainFromChainUrlParam(chainUrlParam?: ChainSlug): ChainInfo | undefined { +export function getChainFromChainUrlParam(chainUrlParam?: ChainSlug): SupportedInterfaceChain | undefined { return chainUrlParam !== undefined ? Object.values(CHAIN_INFO).find((chain) => chainUrlParam === chain.urlParam) : undefined } -export function useChainFromUrlParam(): ChainInfo | undefined { - return getChainFromChainUrlParam(getChainUrlParam(useParams<{ chainName?: string }>().chainName)) +export function useChainFromUrlParam(): SupportedInterfaceChain | undefined { + const chainName = useParams<{ chainName?: string }>().chainName + // In the case where /explore/:chainName is used, the chainName is passed as a tab param + const tab = useParams<{ tab?: string }>().tab + return getChainFromChainUrlParam(getChainUrlParam(chainName ?? tab)) } diff --git a/apps/web/src/constants/providers.ts b/apps/web/src/constants/providers.ts index b1d9846320d..dd3fc575059 100644 --- a/apps/web/src/constants/providers.ts +++ b/apps/web/src/constants/providers.ts @@ -6,7 +6,7 @@ import { CHAIN_IDS_TO_NAMES, CHAIN_INFO, SUPPORTED_INTERFACE_CHAIN_IDS, Supporte function getAppProvider(chainId: SupportedInterfaceChainId) { const info = CHAIN_INFO[chainId] return new AppJsonRpcProvider( - info.rpcUrls.appOnly.map( + info.rpcUrls.appOnly.http.map( (url) => new ConfiguredJsonRpcProvider(url, { chainId, name: CHAIN_IDS_TO_NAMES[chainId] }) ) ) diff --git a/apps/web/src/constants/tokenSafety.tsx b/apps/web/src/constants/tokenSafety.tsx index 8e1c40547c4..ef4acaf37ff 100644 --- a/apps/web/src/constants/tokenSafety.tsx +++ b/apps/web/src/constants/tokenSafety.tsx @@ -34,34 +34,34 @@ export function getWarningCopy(warning: Warning | undefined, plural = false, tok heading = ( ) - description = Always conduct your own research before trading. + description = break case SafetyLevel.StrongWarning: heading = ( ) - description = Always conduct your own research before trading. + description = break case SafetyLevel.Blocked: description = ( ) break @@ -79,19 +79,19 @@ export type Warning = { export const MediumWarning: Warning = { level: SafetyLevel.MediumWarning, - message: Caution, + message: , canProceed: true, } export const StrongWarning: Warning = { level: SafetyLevel.StrongWarning, - message: Warning, + message: , canProceed: true, } export const BlockedWarning: Warning = { level: SafetyLevel.Blocked, - message: Not available, + message: , canProceed: false, } diff --git a/apps/web/src/constants/tokens.ts b/apps/web/src/constants/tokens.ts index eabaaba6486..459b5c95d92 100644 --- a/apps/web/src/constants/tokens.ts +++ b/apps/web/src/constants/tokens.ts @@ -251,6 +251,7 @@ export const DAI_AVALANCHE = new Token( export const UNI: { [chainId: number]: Token } = { [ChainId.MAINNET]: new Token(ChainId.MAINNET, UNI_ADDRESSES[ChainId.MAINNET], 18, 'UNI', 'Uniswap'), + [ChainId.OPTIMISM]: new Token(ChainId.OPTIMISM, UNI_ADDRESSES[ChainId.OPTIMISM], 18, 'UNI', 'Uniswap'), [ChainId.GOERLI]: new Token(ChainId.GOERLI, UNI_ADDRESSES[ChainId.GOERLI], 18, 'UNI', 'Uniswap'), [ChainId.SEPOLIA]: new Token(ChainId.SEPOLIA, UNI_ADDRESSES[ChainId.SEPOLIA], 18, 'UNI', 'Uniswap'), } @@ -371,14 +372,18 @@ class PolygonNativeCurrency extends NativeCurrency { } get wrapped(): Token { - if (!isPolygon(this.chainId)) throw new Error('Not Polygon') + if (!isPolygon(this.chainId)) { + throw new Error('Not Polygon') + } const wrapped = WRAPPED_NATIVE_CURRENCY[this.chainId] invariant(wrapped instanceof Token) return wrapped } public constructor(chainId: number) { - if (!isPolygon(chainId)) throw new Error('Not Polygon') + if (!isPolygon(chainId)) { + throw new Error('Not Polygon') + } super(chainId, 18, 'MATIC', 'Matic') } } @@ -393,14 +398,18 @@ class BscNativeCurrency extends NativeCurrency { } get wrapped(): Token { - if (!isBsc(this.chainId)) throw new Error('Not bnb') + if (!isBsc(this.chainId)) { + throw new Error('Not bnb') + } const wrapped = WRAPPED_NATIVE_CURRENCY[this.chainId] invariant(wrapped instanceof Token) return wrapped } public constructor(chainId: number) { - if (!isBsc(chainId)) throw new Error('Not bnb') + if (!isBsc(chainId)) { + throw new Error('Not bnb') + } super(chainId, 18, 'BNB', 'BNB') } } @@ -415,14 +424,18 @@ class AvaxNativeCurrency extends NativeCurrency { } get wrapped(): Token { - if (!isAvalanche(this.chainId)) throw new Error('Not avalanche') + if (!isAvalanche(this.chainId)) { + throw new Error('Not avalanche') + } const wrapped = WRAPPED_NATIVE_CURRENCY[this.chainId] invariant(wrapped instanceof Token) return wrapped } public constructor(chainId: number) { - if (!isAvalanche(chainId)) throw new Error('Not avalanche') + if (!isAvalanche(chainId)) { + throw new Error('Not avalanche') + } super(chainId, 18, 'AVAX', 'AVAX') } } @@ -430,7 +443,9 @@ class AvaxNativeCurrency extends NativeCurrency { class ExtendedEther extends NativeCurrency { public get wrapped(): Token { const wrapped = WRAPPED_NATIVE_CURRENCY[this.chainId] - if (wrapped) return wrapped + if (wrapped) { + return wrapped + } throw new Error(`Unsupported chain ID: ${this.chainId}`) } @@ -451,7 +466,9 @@ class ExtendedEther extends NativeCurrency { const cachedNativeCurrency: { [chainId: number]: NativeCurrency | Token } = {} export function nativeOnChain(chainId: number): NativeCurrency | Token { - if (cachedNativeCurrency[chainId]) return cachedNativeCurrency[chainId] + if (cachedNativeCurrency[chainId]) { + return cachedNativeCurrency[chainId] + } let nativeCurrency: NativeCurrency | Token if (isPolygon(chainId)) { nativeCurrency = new PolygonNativeCurrency(chainId) diff --git a/apps/web/src/featureFlags/flags/outageBanner.ts b/apps/web/src/featureFlags/flags/outageBanner.ts index e2d9f3d7881..2435ac189d1 100644 --- a/apps/web/src/featureFlags/flags/outageBanner.ts +++ b/apps/web/src/featureFlags/flags/outageBanner.ts @@ -24,8 +24,12 @@ export function useUpdateManualOutage({ const setManualOutage = useUpdateAtom(manualChainOutageAtom) const resetManualOutage = useResetAtom(manualChainOutageAtom) resetManualOutage() - if (errorV3 && chainId) setManualOutage({ chainId }) - if (errorV2 && chainId) setManualOutage({ chainId, version: ProtocolVersion.V2 }) + if (errorV3 && chainId) { + setManualOutage({ chainId }) + } + if (errorV2 && chainId) { + setManualOutage({ chainId, version: ProtocolVersion.V2 }) + } } export function useOutageBanners(): Partial> { diff --git a/apps/web/src/graphql/data/SearchTokens.ts b/apps/web/src/graphql/data/SearchTokens.ts index c0699d394df..869da839ed8 100644 --- a/apps/web/src/graphql/data/SearchTokens.ts +++ b/apps/web/src/graphql/data/SearchTokens.ts @@ -15,20 +15,31 @@ export type SearchToken = NonNullable { - if (!tokens) return undefined + if (!tokens) { + return undefined + } const tokenArray = Array.from(tokens).sort(TokenSortMethods[sortMethod]) return sortAscending ? tokenArray.reverse() : tokenArray @@ -57,14 +59,22 @@ function useFilteredTokens(tokens: TopTokens100Query['topTokens']) { const lowercaseFilterString = useMemo(() => filterString.toLowerCase(), [filterString]) return useMemo(() => { - if (!tokens) return undefined + if (!tokens) { + return undefined + } let returnTokens = tokens if (lowercaseFilterString) { returnTokens = returnTokens?.filter((token) => { const addressIncludesFilterString = token?.address?.toLowerCase().includes(lowercaseFilterString) + const projectNameIncludesFilterString = token?.project?.name?.toLowerCase().includes(lowercaseFilterString) const nameIncludesFilterString = token?.name?.toLowerCase().includes(lowercaseFilterString) const symbolIncludesFilterString = token?.symbol?.toLowerCase().includes(lowercaseFilterString) - return nameIncludesFilterString || symbolIncludesFilterString || addressIncludesFilterString + return ( + projectNameIncludesFilterString || + nameIncludesFilterString || + symbolIncludesFilterString || + addressIncludesFilterString + ) }) } return returnTokens @@ -126,7 +136,9 @@ export function useTopTokens(chain: Chain): UseTopTokensReturnValue { const tokenSortRank = useMemo( () => sortedTokens?.reduce((acc, cur, i) => { - if (!cur?.address) return acc + if (!cur?.address) { + return acc + } return { ...acc, [cur.address]: i + 1, diff --git a/apps/web/src/graphql/data/apollo/AdaptiveRefetch.tsx b/apps/web/src/graphql/data/apollo/AdaptiveRefetch.tsx index 7d6b57b6482..89754c610e9 100644 --- a/apps/web/src/graphql/data/apollo/AdaptiveRefetch.tsx +++ b/apps/web/src/graphql/data/apollo/AdaptiveRefetch.tsx @@ -24,7 +24,9 @@ export function createAdaptiveRefetchContext() { // Tracks whether or not the current query data is undefined or out of date to avoid unnecessary re-fetches. const [isStale, setIsStale] = useState(true) useEffect(() => { - if (stale) setIsStale(true) + if (stale) { + setIsStale(true) + } }, [stale]) // Fetches balances when the query is both stale and subscribed to. @@ -41,7 +43,9 @@ export function createAdaptiveRefetchContext() { }, []) const refetch = useCallback(() => { - if (!isStale) return + if (!isStale) { + return + } fetch() setIsStale(false) }, [fetch, isStale]) @@ -68,12 +72,16 @@ export function createAdaptiveRefetchContext() { */ function useQuery(options?: { cacheOnly?: boolean }) { const context = useContext(Context) - if (!context) throw new Error('useAdaptiveRefetchQuery must be used within an AdaptiveRefetchProvider') + if (!context) { + throw new Error('useAdaptiveRefetchQuery must be used within an AdaptiveRefetchProvider') + } const { subscribe } = context // Subscribing/unsubscribing allows AdaptiveRefetchProvider to track whether components are currently using the query or not, impacting whether or not to re-fetch when stale. useEffect(() => { - if (options?.cacheOnly === true) return + if (options?.cacheOnly === true) { + return + } return subscribe() }, [options?.cacheOnly, subscribe]) @@ -83,7 +91,9 @@ export function createAdaptiveRefetchContext() { /** Fetches the query upon hover, even if no `useQuery` hooks are subscribed. */ function PrefetchWrapper({ children, className }: PropsWithChildren<{ className?: string }>) { const contextValue = useContext(Context) - if (!contextValue) throw new Error('PrefetchWrapper must be used within an AdaptiveRefetchProvider') + if (!contextValue) { + throw new Error('PrefetchWrapper must be used within an AdaptiveRefetchProvider') + } const { refetch } = contextValue return ( diff --git a/apps/web/src/graphql/data/apollo/AssetActivityProvider.tsx b/apps/web/src/graphql/data/apollo/AssetActivityProvider.tsx index 3d8e5c65c8a..2f42608f5ee 100644 --- a/apps/web/src/graphql/data/apollo/AssetActivityProvider.tsx +++ b/apps/web/src/graphql/data/apollo/AssetActivityProvider.tsx @@ -103,7 +103,9 @@ export function useAssetActivity() { const subscribedActivities = useSubscribedActivities() const activities = useMemo(() => { - if (!fetchedActivities) return subscribedActivities + if (!fetchedActivities) { + return subscribedActivities + } return [...subscribedActivities, ...fetchedActivities] }, [subscribedActivities, fetchedActivities]) diff --git a/apps/web/src/graphql/data/apollo/TokenBalancesProvider.tsx b/apps/web/src/graphql/data/apollo/TokenBalancesProvider.tsx index fdabbc6e20b..7467e9f9386 100644 --- a/apps/web/src/graphql/data/apollo/TokenBalancesProvider.tsx +++ b/apps/web/src/graphql/data/apollo/TokenBalancesProvider.tsx @@ -1,6 +1,7 @@ import { useWeb3React } from '@web3-react/core' import { usePendingActivity } from 'components/AccountDrawer/MiniPortfolio/Activity/hooks' import { GQL_MAINNET_CHAINS_MUTABLE } from 'graphql/data/util' +import { useAccount } from 'hooks/useAccount' import { PropsWithChildren, useCallback, useMemo } from 'react' import { OnAssetActivitySubscription, @@ -13,7 +14,6 @@ import { FeatureFlags } from 'uniswap/src/features/gating/flags' import { useFeatureFlag } from 'uniswap/src/features/gating/hooks' import { SUBSCRIPTION_CHAINIDS } from 'utilities/src/apollo/constants' import { usePrevious } from 'utilities/src/react/hooks' -import { useChainId } from 'wagmi' import { createAdaptiveRefetchContext } from './AdaptiveRefetch' import { useAssetActivitySubscription } from './AssetActivityProvider' @@ -38,7 +38,7 @@ function mayAffectTokenBalances(data?: OnAssetActivitySubscription) { } function useIsRealtime() { - const chainId = useChainId() + const { chainId } = useAccount() const isRealtimeEnabled = useFeatureFlag(FeatureFlags.Realtime) return isRealtimeEnabled && chainId && SUBSCRIPTION_CHAINIDS.includes(chainId) @@ -73,7 +73,9 @@ export function TokenBalancesProvider({ children }: PropsWithChildren) { const hasAccountUpdate = useHasAccountUpdate() const fetch = useCallback(() => { - if (!account) return + if (!account) { + return + } lazyFetch({ variables: { ownerAddress: account, chains: GQL_MAINNET_CHAINS_MUTABLE } }) }, [account, lazyFetch]) @@ -88,7 +90,7 @@ export function TokenBalancesProvider({ children }: PropsWithChildren) { * Retrieves cached token balances, avoiding new fetches to reduce backend load. * Analytics should use balances from transaction flows instead of initiating fetches at pageload. */ -export function useTotalBalancesUsdForAnalytics() { +export function useTotalBalancesUsdForAnalytics(): number | undefined { return useTokenBalancesQuery({ cacheOnly: true }).data?.portfolios?.[0]?.tokensTotalDenominatedValue?.value } diff --git a/apps/web/src/graphql/data/nft/Collection.ts b/apps/web/src/graphql/data/nft/Collection.ts index 555ccfb6288..de106143c1c 100644 --- a/apps/web/src/graphql/data/nft/Collection.ts +++ b/apps/web/src/graphql/data/nft/Collection.ts @@ -10,7 +10,9 @@ export function formatCollectionQueryData( address?: string ): GenieCollection { const market = queryCollection?.markets?.[0] - if (!address && !queryCollection?.nftContracts?.[0]?.address) return {} as GenieCollection + if (!address && !queryCollection?.nftContracts?.[0]?.address) { + return {} as GenieCollection + } const traits = {} as Record if (queryCollection?.traits) { queryCollection?.traits.forEach((trait) => { diff --git a/apps/web/src/graphql/data/nft/NftUniversalRouterAddress.ts b/apps/web/src/graphql/data/nft/NftUniversalRouterAddress.ts index 96b7b7a9d04..91c1bb8eae9 100644 --- a/apps/web/src/graphql/data/nft/NftUniversalRouterAddress.ts +++ b/apps/web/src/graphql/data/nft/NftUniversalRouterAddress.ts @@ -4,7 +4,9 @@ import { SupportedInterfaceChainId } from 'constants/chains' import { useNftUniversalRouterAddressQuery } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' export function getURAddress(chainId?: SupportedInterfaceChainId, nftURAddress?: string): string | undefined { - if (!chainId) return undefined + if (!chainId) { + return undefined + } // if mainnet and on NFT flow, use the contract address returned by GQL if (chainId === ChainId.MAINNET) { return nftURAddress ?? UNIVERSAL_ROUTER_ADDRESS(chainId) diff --git a/apps/web/src/graphql/data/pools/usePoolTransactions.ts b/apps/web/src/graphql/data/pools/usePoolTransactions.ts index 8eb7413a889..a69b74a56d5 100644 --- a/apps/web/src/graphql/data/pools/usePoolTransactions.ts +++ b/apps/web/src/graphql/data/pools/usePoolTransactions.ts @@ -92,7 +92,9 @@ export function usePoolTransactions( cursor: transactions?.[transactions.length - 1]?.timestamp, }, updateQuery: (prev, { fetchMoreResult }: any) => { - if (!fetchMoreResult) return prev + if (!fetchMoreResult) { + return prev + } onComplete?.() const mergedData = protocolVersion === ProtocolVersion.V3 @@ -138,7 +140,9 @@ export function usePoolTransactions( : tx.type === PoolTransactionType.Remove ? PoolTableTransactionType.BURN : PoolTableTransactionType.MINT - if (!filter.includes(type)) return undefined + if (!filter.includes(type)) { + return undefined + } return { timestamp: tx.timestamp, transaction: tx.hash, diff --git a/apps/web/src/graphql/data/pools/usePoolsFromTokenAddress.ts b/apps/web/src/graphql/data/pools/usePoolsFromTokenAddress.ts index c251d9a4fef..1912a08e1b9 100644 --- a/apps/web/src/graphql/data/pools/usePoolsFromTokenAddress.ts +++ b/apps/web/src/graphql/data/pools/usePoolsFromTokenAddress.ts @@ -61,8 +61,12 @@ export function usePoolsFromTokenAddress( cursor: dataV3?.topV3Pools?.[dataV3.topV3Pools.length - 1]?.totalLiquidity?.value, }, updateQuery: (prev, { fetchMoreResult }) => { - if (!fetchMoreResult || !prev || !Object.keys(prev).length) return prev - if (!loadingMoreV2.current || (chainId !== ChainId.MAINNET && !v2ExploreEnabled)) onComplete?.() + if (!fetchMoreResult || !prev || !Object.keys(prev).length) { + return prev + } + if (!loadingMoreV2.current || (chainId !== ChainId.MAINNET && !v2ExploreEnabled)) { + onComplete?.() + } const mergedData = { topV3Pools: [...(prev.topV3Pools ?? []).slice(), ...(fetchMoreResult.topV3Pools ?? []).slice()], } @@ -76,8 +80,12 @@ export function usePoolsFromTokenAddress( cursor: dataV2?.topV2Pairs?.[dataV2.topV2Pairs.length - 1]?.totalLiquidity?.value, }, updateQuery: (prev, { fetchMoreResult }) => { - if (!fetchMoreResult || !prev || !Object.keys(prev).length) return prev - if (!loadingMoreV3.current) onComplete?.() + if (!fetchMoreResult || !prev || !Object.keys(prev).length) { + return prev + } + if (!loadingMoreV3.current) { + onComplete?.() + } const mergedData = { topV2Pairs: [...(prev.topV2Pairs ?? []).slice(), ...(fetchMoreResult.topV2Pairs ?? []).slice()], } diff --git a/apps/web/src/graphql/data/pools/useTopPools.ts b/apps/web/src/graphql/data/pools/useTopPools.ts index de0acebdd57..a7025f55407 100644 --- a/apps/web/src/graphql/data/pools/useTopPools.ts +++ b/apps/web/src/graphql/data/pools/useTopPools.ts @@ -48,7 +48,9 @@ export function sortPools(pools: TablePool[], sortState: PoolTableSortState) { * @returns 1 day APR expressed as a percent */ export function calculateOneDayApr(volume24h?: number, tvl?: number, feeTier?: number): Percent { - if (!volume24h || !feeTier || !tvl || !Math.round(tvl)) return new Percent(0) + if (!volume24h || !feeTier || !tvl || !Math.round(tvl)) { + return new Percent(0) + } return new Percent(Math.round(volume24h * (feeTier / BIPS_BASE)), Math.round(tvl)) } diff --git a/apps/web/src/graphql/data/useAllTransactions.ts b/apps/web/src/graphql/data/useAllTransactions.ts index 936630aa4cf..5852dd35733 100644 --- a/apps/web/src/graphql/data/useAllTransactions.ts +++ b/apps/web/src/graphql/data/useAllTransactions.ts @@ -66,8 +66,12 @@ export function useAllTransactions( cursor: dataV3?.v3Transactions?.[dataV3.v3Transactions.length - 1]?.timestamp, }, updateQuery: (prev, { fetchMoreResult }) => { - if (!fetchMoreResult) return prev - if (!loadingMoreV2.current || (chain !== Chain.Ethereum && !v2ExploreEnabled)) onComplete?.() + if (!fetchMoreResult) { + return prev + } + if (!loadingMoreV2.current || (chain !== Chain.Ethereum && !v2ExploreEnabled)) { + onComplete?.() + } const mergedData = { v3Transactions: [...(prev.v3Transactions ?? []), ...(fetchMoreResult.v3Transactions ?? [])], } @@ -81,7 +85,9 @@ export function useAllTransactions( cursor: dataV2?.v2Transactions?.[dataV2.v2Transactions.length - 1]?.timestamp, }, updateQuery: (prev, { fetchMoreResult }) => { - if (!fetchMoreResult) return prev + if (!fetchMoreResult) { + return prev + } !loadingMoreV3.current && onComplete?.() const mergedData = { v2Transactions: [...(prev.v2Transactions ?? []), ...(fetchMoreResult.v2Transactions ?? [])], diff --git a/apps/web/src/graphql/data/useTokenTransactions.ts b/apps/web/src/graphql/data/useTokenTransactions.ts index f75ffc64a0c..f2f17e9f1a7 100644 --- a/apps/web/src/graphql/data/useTokenTransactions.ts +++ b/apps/web/src/graphql/data/useTokenTransactions.ts @@ -68,7 +68,9 @@ export function useTokenTransactions( if (!fetchMoreResult) { return prev } - if (!loadingMoreV2.current || (chainId !== ChainId.MAINNET && !v2ExploreEnabled)) onComplete?.() + if (!loadingMoreV2.current || (chainId !== ChainId.MAINNET && !v2ExploreEnabled)) { + onComplete?.() + } const mergedData = { token: { ...prev.token, @@ -87,8 +89,12 @@ export function useTokenTransactions( cursor: dataV2?.token?.v2Transactions?.[dataV2.token?.v2Transactions.length - 1]?.timestamp, }, updateQuery: (prev, { fetchMoreResult }) => { - if (!fetchMoreResult) return prev - if (!loadingMoreV3.current) onComplete?.() + if (!fetchMoreResult) { + return prev + } + if (!loadingMoreV3.current) { + onComplete?.() + } const mergedData = { token: { ...prev.token, @@ -116,7 +122,7 @@ export function useTokenTransactions( if (!tx) { return false } - const tokenBeingSold = parseFloat(tx.token0Quantity) < 0 ? tx.token0 : tx.token1 + const tokenBeingSold = parseFloat(tx.token0Quantity) > 0 ? tx.token0 : tx.token1 const isSell = tokenBeingSold.address?.toLowerCase() === address.toLowerCase() return ( tx.type === PoolTransactionType.Swap && @@ -127,7 +133,7 @@ export function useTokenTransactions( if (!tx) { return false } - const tokenBeingSold = parseFloat(tx.token0Quantity) < 0 ? tx.token0 : tx.token1 + const tokenBeingSold = parseFloat(tx.token0Quantity) > 0 ? tx.token0 : tx.token1 const isSell = tokenBeingSold.address?.toLowerCase() === address.toLowerCase() return ( tx.type === PoolTransactionType.Swap && diff --git a/apps/web/src/graphql/data/util.test.tsx b/apps/web/src/graphql/data/util.test.tsx index 69ee6188a3f..f9bbf77566d 100644 --- a/apps/web/src/graphql/data/util.test.tsx +++ b/apps/web/src/graphql/data/util.test.tsx @@ -7,7 +7,9 @@ describe('fromGraphQLChain', () => { expect(supportedChainIdFromGQLChain(Chain.Ethereum)).toBe(ChainId.MAINNET) for (const chain of Object.values(Chain)) { - if (!isSupportedGQLChain(chain)) continue + if (!isSupportedGQLChain(chain)) { + continue + } expect(supportedChainIdFromGQLChain(chain)).not.toBe(undefined) } }) @@ -16,7 +18,9 @@ describe('fromGraphQLChain', () => { expect(supportedChainIdFromGQLChain(Chain.UnknownChain)).toBe(undefined) for (const chain of Object.values(Chain)) { - if (isSupportedGQLChain(chain)) continue + if (isSupportedGQLChain(chain)) { + continue + } expect(supportedChainIdFromGQLChain(chain)).toBe(undefined) } }) @@ -28,7 +32,9 @@ describe('fromGraphQLChain', () => { const ExpandedChainList = [...Object.values(Chain), NewChain.NewChain as unknown as Chain] for (const chain of ExpandedChainList) { - if (isSupportedGQLChain(chain)) continue + if (isSupportedGQLChain(chain)) { + continue + } expect(supportedChainIdFromGQLChain(chain)).toBe(undefined) } }) diff --git a/apps/web/src/graphql/data/util.tsx b/apps/web/src/graphql/data/util.tsx index e2d3caeb098..5824c7a9db8 100644 --- a/apps/web/src/graphql/data/util.tsx +++ b/apps/web/src/graphql/data/util.tsx @@ -8,9 +8,9 @@ import { BACKEND_SUPPORTED_CHAINS, CHAIN_INFO, CHAIN_NAME_TO_CHAIN_ID, - ChainInfo, GQL_MAINNET_CHAINS, InterfaceGqlChain, + SupportedInterfaceChain, SupportedInterfaceChainId, UX_SUPPORTED_GQL_CHAINS, chainIdToBackendChain, @@ -95,27 +95,38 @@ export function toContractInput(currency: Currency): ContractInput { } export function gqlToCurrency(token: DeepPartial): Currency | undefined { - if (!token.chain) return undefined + if (!token.chain) { + return undefined + } const chainId = supportedChainIdFromGQLChain(token.chain) - if (!chainId) return undefined - if (token.standard === TokenStandard.Native || token.address === NATIVE_CHAIN_ID || !token.address) + if (!chainId) { + return undefined + } + if (token.standard === TokenStandard.Native || token.address === NATIVE_CHAIN_ID || !token.address) { return nativeOnChain(chainId) - else + } else { return new Token( chainId, token.address, token.decimals ?? 18, token.symbol ?? undefined, - token.name ?? token.project?.name ?? undefined + token.project?.name ?? token.name ?? undefined ) + } } -export function getSupportedGraphQlChain(chain: ChainInfo | undefined, options?: undefined): ChainInfo | undefined -export function getSupportedGraphQlChain(chain: ChainInfo | undefined, options: { fallbackToEthereum: true }): ChainInfo export function getSupportedGraphQlChain( - chain: ChainInfo | undefined, + chain: SupportedInterfaceChain | undefined, + options?: undefined +): SupportedInterfaceChain | undefined +export function getSupportedGraphQlChain( + chain: SupportedInterfaceChain | undefined, + options: { fallbackToEthereum: true } +): SupportedInterfaceChain +export function getSupportedGraphQlChain( + chain: SupportedInterfaceChain | undefined, options?: { fallbackToEthereum?: boolean } -): ChainInfo | undefined { +): SupportedInterfaceChain | undefined { const fallbackChain = options?.fallbackToEthereum ? CHAIN_INFO[ChainId.MAINNET] : undefined return chain?.backendChain.backendSupported ? chain : fallbackChain } @@ -180,19 +191,29 @@ export function unwrapToken< T extends | { address?: string | null + project?: { name?: string | null } } | undefined >(chainId: number, token: T): T { - if (!token?.address) return token + if (!token?.address) { + return token + } const address = token.address.toLowerCase() const nativeAddress = WRAPPED_NATIVE_CURRENCY[chainId]?.address.toLowerCase() - if (address !== nativeAddress) return token + if (address !== nativeAddress) { + return token + } const nativeToken = nativeOnChain(chainId) + return { ...token, ...nativeToken, + project: { + ...token.project, + name: nativeToken.name, + }, address: NATIVE_CHAIN_ID, extensions: undefined, // prevents marking cross-chain wrapped tokens as native } diff --git a/apps/web/src/hooks/Tokens.ts b/apps/web/src/hooks/Tokens.ts index d78f5e8b4da..2b189b282af 100644 --- a/apps/web/src/hooks/Tokens.ts +++ b/apps/web/src/hooks/Tokens.ts @@ -1,9 +1,16 @@ import { ChainId, Currency, Token } from '@uniswap/sdk-core' -import { chainIdToBackendChain, getChainInfo, isSupportedChainId, useSupportedChainId } from 'constants/chains' +import { + SupportedInterfaceChainId, + chainIdToBackendChain, + getChain, + isSupportedChainId, + useSupportedChainId, +} from 'constants/chains' import { COMMON_BASES } from 'constants/routing' import { NATIVE_CHAIN_ID, UNKNOWN_TOKEN_SYMBOL } from 'constants/tokens' import { arrayify, parseBytes32String } from 'ethers/lib/utils' import { gqlTokenToCurrencyInfo } from 'graphql/data/types' +import { useAccount } from 'hooks/useAccount' import { useBytes32TokenContract, useTokenContract } from 'hooks/useContract' import { NEVER_RELOAD, useSingleCallResult } from 'lib/hooks/multicall' import { TokenAddressMap } from 'lib/hooks/useTokenList/utils' @@ -19,7 +26,6 @@ import { isAddress, isSameAddress } from 'utilities/src/addresses' import { DEFAULT_ERC20_DECIMALS } from 'utilities/src/tokens/constants' import { currencyId } from 'utils/currencyId' import { getNativeTokenDBAddress } from 'utils/nativeTokens' -import { useChainId } from 'wagmi' import { useCombinedInactiveLists } from '../state/lists/hooks' import { useUserAddedTokens } from '../state/user/userAddedTokens' @@ -28,7 +34,9 @@ type Maybe = T | undefined // reduce token map into standard address <-> Token mapping, optionally include user added tokens function useTokensFromMap(tokenMap: TokenAddressMap, chainId: Maybe): { [address: string]: TokenFromList } { return useMemo(() => { - if (!chainId) return {} + if (!chainId) { + return {} + } // reduce to just tokens return Object.keys(tokenMap[chainId] ?? {}).reduce<{ [address: string]: TokenFromList }>((newMap, address) => { @@ -86,7 +94,7 @@ export function useCurrencyInfo( chainId?: ChainId, skip?: boolean ): Maybe { - const connectedChainId = useChainId() + const { chainId: connectedChainId } = useAccount() const fallbackListTokens = useFallbackListTokens(chainId ?? connectedChainId) const address = @@ -124,7 +132,7 @@ export function useCurrencyInfo( (!address && !isNative) || skip || !!commonBase || - !getChainInfo({ chainId: supportedChainId })?.backendChain.backendSupported, + !getChain({ chainId: supportedChainId })?.backendChain.backendSupported, fetchPolicy: 'cache-first', }) @@ -152,14 +160,14 @@ export function useCurrencyInfo( }, [commonBase, fallbackListTokens, address, skip, data?.token]) } -export function useToken(tokenAddress?: string, chainId?: ChainId): Maybe { - const connectedChainId = useChainId() +export function useToken(tokenAddress?: string, chainId?: SupportedInterfaceChainId): Maybe { + const { chainId: connectedChainId } = useAccount() const currency = useCurrency(tokenAddress, chainId ?? connectedChainId) // Some chains are not supported by the backend, so we need to fetch token // details directly from the blockchain. const networkToken = useTokenFromActiveNetwork( tokenAddress, - getChainInfo({ chainId: chainId ?? connectedChainId })?.backendChain.backendSupported + getChain({ chainId: chainId ?? connectedChainId })?.backendChain.backendSupported ) return useMemo(() => { if (currency && currency instanceof Token) { @@ -189,7 +197,7 @@ const UNKNOWN_TOKEN_NAME = 'Unknown Token' * Returns undefined if tokenAddress is invalid or token does not exist. */ function useTokenFromActiveNetwork(tokenAddress: string | undefined, skip?: boolean): Token | undefined { - const chainId = useChainId() + const { chainId } = useAccount() const formattedAddress = isAddress(tokenAddress) const tokenContract = useTokenContract(formattedAddress ? formattedAddress : undefined, false) @@ -220,8 +228,12 @@ function useTokenFromActiveNetwork(tokenAddress: string | undefined, skip?: bool return useMemo(() => { // If the token is on another chain, we cannot fetch it on-chain, and it is invalid. - if (!tokenAddress || !isSupportedChainId(chainId) || !formattedAddress) return undefined - if (isLoading || !chainId) return undefined + if (!tokenAddress || !isSupportedChainId(chainId) || !formattedAddress) { + return undefined + } + if (isLoading || !chainId) { + return undefined + } if (!decimals?.result?.[0] && parsedSymbol === UNKNOWN_TOKEN_SYMBOL && parsedName === UNKNOWN_TOKEN_NAME) { return undefined } diff --git a/apps/web/src/hooks/useAccount.ts b/apps/web/src/hooks/useAccount.ts new file mode 100644 index 00000000000..a2a2a3f1a8a --- /dev/null +++ b/apps/web/src/hooks/useAccount.ts @@ -0,0 +1,27 @@ +/* eslint-disable rulesdir/no-undefined-or */ +import { SupportedInterfaceChainId, useSupportedChainId } from 'constants/chains' +import { useMemo } from 'react' +// eslint-disable-next-line @typescript-eslint/no-restricted-imports +import { UseAccountReturnType as UseAccountReturnTypeWagmi, useAccount as useAccountWagmi, useChainId } from 'wagmi' + +type ReplaceChainId = T extends { chainId: number } + ? Omit & { chainId: SupportedInterfaceChainId | undefined } + : T extends { chainId: number | undefined } + ? Omit & { chainId: SupportedInterfaceChainId | undefined } + : T + +type UseAccountReturnType = ReplaceChainId + +export function useAccount(): UseAccountReturnType { + const { chainId, ...rest } = useAccountWagmi() + const fallbackChainId = useChainId() + const supportedChainId = useSupportedChainId(chainId ?? fallbackChainId) + + return useMemo( + () => ({ + ...rest, + chainId: supportedChainId, + }), + [rest, supportedChainId] + ) +} diff --git a/apps/web/src/hooks/useAccountRiskCheck.ts b/apps/web/src/hooks/useAccountRiskCheck.ts index c39a6fff3bf..8e006872683 100644 --- a/apps/web/src/hooks/useAccountRiskCheck.ts +++ b/apps/web/src/hooks/useAccountRiskCheck.ts @@ -6,7 +6,9 @@ export default function useAccountRiskCheck(account: string | null | undefined) const dispatch = useAppDispatch() useEffect(() => { - if (!account) return + if (!account) { + return + } // TODO: add back local browser cacheing (revisit 11/13/2023) const headers = new Headers({ 'Content-Type': 'application/json' }) diff --git a/apps/web/src/hooks/useActiveLocalCurrency.ts b/apps/web/src/hooks/useActiveLocalCurrency.ts index 72d06bb3267..0978154d3b6 100644 --- a/apps/web/src/hooks/useActiveLocalCurrency.ts +++ b/apps/web/src/hooks/useActiveLocalCurrency.ts @@ -15,7 +15,9 @@ function useUrlLocalCurrency() { const parsed = useParsedQueryString() const parsedLocalCurrency = parsed.cur - if (typeof parsedLocalCurrency !== 'string') return undefined + if (typeof parsedLocalCurrency !== 'string') { + return undefined + } const lowerCaseSupportedLocalCurrency = parsedLocalCurrency.toLowerCase() return SUPPORTED_LOCAL_CURRENCIES.find( diff --git a/apps/web/src/hooks/useActiveLocale.ts b/apps/web/src/hooks/useActiveLocale.ts index 95f1aa8fcb6..5c9def3130d 100644 --- a/apps/web/src/hooks/useActiveLocale.ts +++ b/apps/web/src/hooks/useActiveLocale.ts @@ -3,14 +3,16 @@ import { useMemo } from 'react' import store from 'state' import { useUserLocale } from 'state/user/hooks' -import useParsedQueryString, { parsedQueryString } from './useParsedQueryString' +import useParsedQueryString from './useParsedQueryString' /** * Given a locale string (e.g. from user agent), return the best match for corresponding SupportedLocale * @param maybeSupportedLocale the fuzzy locale identifier */ -function parseLocale(maybeSupportedLocale: unknown): SupportedLocale | undefined { - if (typeof maybeSupportedLocale !== 'string') return undefined +export function parseLocale(maybeSupportedLocale: unknown): SupportedLocale | undefined { + if (typeof maybeSupportedLocale !== 'string') { + return undefined + } const lowerMaybeSupportedLocale = maybeSupportedLocale.toLowerCase() return SUPPORTED_LOCALES.find( (locale) => locale.toLowerCase() === lowerMaybeSupportedLocale || locale.split('-')[0] === lowerMaybeSupportedLocale @@ -21,7 +23,9 @@ function parseLocale(maybeSupportedLocale: unknown): SupportedLocale | undefined * Returns the supported locale read from the user agent (navigator) */ export function navigatorLocale(): SupportedLocale | undefined { - if (!navigator.language) return undefined + if (!navigator.language) { + return undefined + } const [language, region] = navigator.language.split('-') @@ -32,13 +36,10 @@ export function navigatorLocale(): SupportedLocale | undefined { return parseLocale(language) } -function storeLocale(): SupportedLocale | undefined { +export function storeLocale(): SupportedLocale | undefined { return store.getState().user.userLocale ?? undefined } -export const initialLocale = - parseLocale(parsedQueryString().lng) ?? storeLocale() ?? navigatorLocale() ?? DEFAULT_LOCALE - function useUrlLocale() { const parsed = useParsedQueryString() return parseLocale(parsed.lng) diff --git a/apps/web/src/hooks/useAutoRouterSupported.tsx b/apps/web/src/hooks/useAutoRouterSupported.tsx index 5dfde5621f4..22000faa97e 100644 --- a/apps/web/src/hooks/useAutoRouterSupported.tsx +++ b/apps/web/src/hooks/useAutoRouterSupported.tsx @@ -1,7 +1,6 @@ -import { useIsSupportedChainId } from 'constants/chains' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' export default function useAutoRouterSupported(): boolean { - const chainId = useChainId() - return useIsSupportedChainId(chainId) + const { chainId } = useAccount() + return !!chainId } diff --git a/apps/web/src/hooks/useAutoSlippageTolerance.ts b/apps/web/src/hooks/useAutoSlippageTolerance.ts index 6ad61325966..766b255107e 100644 --- a/apps/web/src/hooks/useAutoSlippageTolerance.ts +++ b/apps/web/src/hooks/useAutoSlippageTolerance.ts @@ -7,8 +7,8 @@ import JSBI from 'jsbi' import useNativeCurrency from 'lib/hooks/useNativeCurrency' import { useMemo } from 'react' import { ClassicTrade } from 'state/routing/types' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import useGasPrice from './useGasPrice' import { useStablecoinAmountFromFiatValue } from './useStablecoinPrice' import { useUSDPrice } from './useUSDPrice' @@ -74,7 +74,7 @@ const MAX_AUTO_SLIPPAGE_TOLERANCE = new Percent(5, 100) // 5% * Auto slippage is only relevant for Classic swaps because UniswapX slippage is determined by the backend service */ export default function useClassicAutoSlippageTolerance(trade?: ClassicTrade): Percent { - const chainId = useChainId() + const { chainId } = useAccount() const onL2 = chainId && L2_CHAIN_IDS.includes(chainId) const outputUSD = useUSDPrice(trade?.outputAmount) const outputDollarValue = useStablecoinAmountFromFiatValue(outputUSD.data) @@ -99,7 +99,9 @@ export default function useClassicAutoSlippageTolerance(trade?: ClassicTrade): P const gasCostStablecoinAmount = useStablecoinAmountFromFiatValue(gasCostUSD.data) return useMemo(() => { - if (!trade || onL2) return DEFAULT_AUTO_SLIPPAGE + if (!trade || onL2) { + return DEFAULT_AUTO_SLIPPAGE + } // if valid estimate from api and using api trade, use gas estimate from api // NOTE - dont use gas estimate for L2s yet - need to verify accuracy diff --git a/apps/web/src/hooks/useConfirmModalState.ts b/apps/web/src/hooks/useConfirmModalState.ts index 0faf75d64a8..aba4415c379 100644 --- a/apps/web/src/hooks/useConfirmModalState.ts +++ b/apps/web/src/hooks/useConfirmModalState.ts @@ -1,21 +1,21 @@ import { InterfaceEventName } from '@uniswap/analytics-events' import { Currency, Percent } from '@uniswap/sdk-core' -import { sendAnalyticsEvent, useTrace } from 'analytics' import { ConfirmModalState } from 'components/ConfirmSwapModal' import { PendingModalError } from 'components/ConfirmSwapModal/Error' import { Field, RESET_APPROVAL_TOKENS } from 'components/swap/constants' +import { useAccount } from 'hooks/useAccount' import useNativeCurrency from 'lib/hooks/useNativeCurrency' import { getPriceUpdateBasisPoints } from 'lib/utils/analytics' import { useCallback, useEffect, useState } from 'react' import { InterfaceTrade } from 'state/routing/types' +import { isUniswapXTrade } from 'state/routing/utils' import { useIsTransactionConfirmed } from 'state/transactions/hooks' import invariant from 'tiny-invariant' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { NumberType, useFormatter } from 'utils/formatNumbers' import { didUserReject } from 'utils/swapErrorToUserReadableMessage' import { tradeMeaningfullyDiffers } from 'utils/tradeMeaningFullyDiffer' -import { useChainId } from 'wagmi' - -import { isUniswapXTrade } from 'state/routing/utils' import { useMaxAmountIn } from './useMaxAmountIn' import { Allowance, AllowanceState } from './usePermit2Allowance' import usePrevious from './usePrevious' @@ -76,7 +76,7 @@ export function useConfirmModalState({ return steps }, [allowance, trade]) - const chainId = useChainId() + const { chainId } = useAccount() const trace = useTrace() const maximumAmountIn = useMaxAmountIn(trade, allowedSlippage) @@ -95,7 +95,9 @@ export function useConfirmModalState({ const prevWrapConfirmed = usePrevious(wrapConfirmed) const catchUserReject = async (e: any, errorType: PendingModalError) => { setConfirmModalState(ConfirmModalState.REVIEWING) - if (didUserReject(e)) return + if (didUserReject(e)) { + return + } console.error(e) setApprovalError(errorType) } diff --git a/apps/web/src/hooks/useContract.ts b/apps/web/src/hooks/useContract.ts index b92af74dd86..864399b0d50 100644 --- a/apps/web/src/hooks/useContract.ts +++ b/apps/web/src/hooks/useContract.ts @@ -15,9 +15,9 @@ import NonfungiblePositionManagerJson from '@uniswap/v3-periphery/artifacts/cont import V3MigratorJson from '@uniswap/v3-periphery/artifacts/contracts/V3Migrator.sol/V3Migrator.json' import UniswapInterfaceMulticallJson from '@uniswap/v3-periphery/artifacts/contracts/lens/UniswapInterfaceMulticall.sol/UniswapInterfaceMulticall.json' import { useWeb3React } from '@web3-react/core' -import { sendAnalyticsEvent } from 'analytics' import { RPC_PROVIDERS } from 'constants/providers' import { WRAPPED_NATIVE_CURRENCY } from 'constants/tokens' +import { useAccount } from 'hooks/useAccount' import { useEthersProvider } from 'hooks/useEthersProvider' import { useEffect, useMemo } from 'react' import ARGENT_WALLET_DETECTOR_ABI from 'uniswap/src/abis/argent-wallet-detector.json' @@ -40,8 +40,8 @@ import { import { NonfungiblePositionManager, UniswapInterfaceMulticall } from 'uniswap/src/abis/types/v3' import { V3Migrator } from 'uniswap/src/abis/types/v3/V3Migrator' import WETH_ABI from 'uniswap/src/abis/weth.json' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { getContract } from 'utilities/src/contracts/getContract' -import { useAccount, useChainId } from 'wagmi' const { abi: IUniswapV2PairABI } = IUniswapV2PairJson const { abi: IUniswapV2Router02ABI } = IUniswapV2Router02Json @@ -56,30 +56,28 @@ export function useContract( withSignerIfPossible = true ): T | null { const account = useAccount() - const disconnectedChainId = useChainId() const provider = useEthersProvider() return useMemo(() => { - if (!addressOrAddressMap || !ABI || !provider) return null + if (!addressOrAddressMap || !ABI || !provider || !account.chainId) { + return null + } let address: string | undefined - if (typeof addressOrAddressMap === 'string') address = addressOrAddressMap - else address = addressOrAddressMap[account.chainId ?? disconnectedChainId] - if (!address) return null + if (typeof addressOrAddressMap === 'string') { + address = addressOrAddressMap + } else { + address = addressOrAddressMap[account.chainId] + } + if (!address) { + return null + } try { return getContract(address, ABI, provider, withSignerIfPossible && account.address ? account.address : undefined) } catch (error) { console.error('Failed to get contract', error) return null } - }, [ - addressOrAddressMap, - ABI, - provider, - account.chainId, - account.address, - disconnectedChainId, - withSignerIfPossible, - ]) as T + }, [addressOrAddressMap, ABI, provider, account.chainId, account.address, withSignerIfPossible]) as T } function useMainnetContract(address: string | undefined, ABI: any): T | null { @@ -88,8 +86,12 @@ function useMainnetContract(address: string | und const contract = useContract(isMainnet ? address : undefined, ABI, false) return useMemo(() => { - if (isMainnet) return contract - if (!address) return null + if (isMainnet) { + return contract + } + if (!address) { + return null + } const provider = RPC_PROVIDERS[ChainId.MAINNET] try { return getContract(address, ABI, provider) diff --git a/apps/web/src/hooks/useDebouncedTrade.ts b/apps/web/src/hooks/useDebouncedTrade.ts index 1d7d5be4507..3e3ff8e7e66 100644 --- a/apps/web/src/hooks/useDebouncedTrade.ts +++ b/apps/web/src/hooks/useDebouncedTrade.ts @@ -1,6 +1,7 @@ import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core' import { routingPreferencesAtom } from 'components/Settings/MultipleRoutingOptions' import { WRAPPED_NATIVE_CURRENCY } from 'constants/tokens' +import { useAccount } from 'hooks/useAccount' import { useAtomValue } from 'jotai/utils' import { useMemo } from 'react' import { ClassicTrade, InterfaceTrade, QuoteMethod, RouterPreference, TradeState } from 'state/routing/types' @@ -9,7 +10,6 @@ import { useRoutingAPITrade } from 'state/routing/useRoutingAPITrade' import { useRouterPreference } from 'state/user/hooks' import { FeatureFlags } from 'uniswap/src/features/gating/flags' import { useFeatureFlag } from 'uniswap/src/features/gating/hooks' -import { useChainId } from 'wagmi' import useAutoRouterSupported from './useAutoRouterSupported' import useDebounce from './useDebounce' @@ -67,7 +67,7 @@ export function useDebouncedTrade( method?: QuoteMethod swapQuoteLatency?: number } { - const chainId = useChainId() + const { chainId } = useAccount() const autoRouterSupported = useAutoRouterSupported() const inputs = useMemo<[CurrencyAmount | undefined, Currency | undefined]>( @@ -79,7 +79,9 @@ export function useDebouncedTrade( const isPreviewTradeDebouncing = useDebounce(inputs, DEBOUNCE_TIME_QUICKROUTE) !== inputs const isWrap = useMemo(() => { - if (!chainId || !amountSpecified || !otherCurrency) return false + if (!chainId || !amountSpecified || !otherCurrency) { + return false + } const weth = WRAPPED_NATIVE_CURRENCY[chainId] return Boolean( (amountSpecified.currency.isNative && weth?.equals(otherCurrency)) || diff --git a/apps/web/src/hooks/useDisableScrolling.ts b/apps/web/src/hooks/useDisableScrolling.ts index ad2cc087952..65c302fd77d 100644 --- a/apps/web/src/hooks/useDisableScrolling.ts +++ b/apps/web/src/hooks/useDisableScrolling.ts @@ -4,7 +4,9 @@ import { isMobile } from 'uniswap/src/utils/platform' /** Disables scrolling of the main body on mobile when `true` is passed. Generally used for modals. */ export default function useDisableScrolling(disable: boolean | undefined | null) { useEffect(() => { - if (!isMobile) return + if (!isMobile) { + return + } document.body.style.overflow = disable ? 'hidden' : 'auto' }, [disable]) } diff --git a/apps/web/src/hooks/useENSAvatar.ts b/apps/web/src/hooks/useENSAvatar.ts index fe76dd04cd3..7d39a73363f 100644 --- a/apps/web/src/hooks/useENSAvatar.ts +++ b/apps/web/src/hooks/useENSAvatar.ts @@ -22,7 +22,9 @@ export default function useENSAvatar( ): { avatar: string | null; loading: boolean } { const debouncedAddress = useDebounce(address, 200) const node = useMemo(() => { - if (!debouncedAddress || !isAddress(debouncedAddress)) return undefined + if (!debouncedAddress || !isAddress(debouncedAddress)) { + return undefined + } return safeNamehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`) }, [debouncedAddress]) diff --git a/apps/web/src/hooks/useENSName.ts b/apps/web/src/hooks/useENSName.ts index 680b53270e3..a6626375a8c 100644 --- a/apps/web/src/hooks/useENSName.ts +++ b/apps/web/src/hooks/useENSName.ts @@ -15,7 +15,9 @@ import useENSAddress from './useENSAddress' export default function useENSName(address?: string): { ENSName: string | null; loading: boolean } { const debouncedAddress = useDebounce(address, 200) const ensNodeArgument = useMemo(() => { - if (!debouncedAddress || !isAddress(debouncedAddress)) return [undefined] + if (!debouncedAddress || !isAddress(debouncedAddress)) { + return [undefined] + } return [safeNamehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`)] }, [debouncedAddress]) const registrarContract = useENSRegistrarContract() diff --git a/apps/web/src/hooks/useERC20Permit.ts b/apps/web/src/hooks/useERC20Permit.ts index aca42c9f9f8..b682d79c288 100644 --- a/apps/web/src/hooks/useERC20Permit.ts +++ b/apps/web/src/hooks/useERC20Permit.ts @@ -1,12 +1,12 @@ import { BigNumber } from '@ethersproject/bignumber' import { splitSignature } from '@ethersproject/bytes' import { ChainId, Currency, CurrencyAmount } from '@uniswap/sdk-core' +import { useAccount } from 'hooks/useAccount' +import { useEthersWeb3Provider } from 'hooks/useEthersProvider' import JSBI from 'jsbi' import { useSingleCallResult } from 'lib/hooks/multicall' import { useMemo, useState } from 'react' -import { useEthersWeb3Provider } from 'hooks/useEthersProvider' -import { useAccount } from 'wagmi' import { DAI, UNI, USDC_MAINNET } from '../constants/tokens' import { useEIP2612Contract } from './useContract' import useIsArgentWallet from './useIsArgentWallet' @@ -115,16 +115,16 @@ export function useERC20Permit( state: UseERC20PermitState gatherPermitSignature: null | (() => Promise) } { - const account = useAccount() + const { status, chainId, address } = useAccount() const provider = useEthersWeb3Provider() const tokenAddress = currencyAmount?.currency?.isToken ? currencyAmount.currency.address : undefined const eip2612Contract = useEIP2612Contract(tokenAddress) const isArgentWallet = useIsArgentWallet() - const nonceInputs = useMemo(() => [account.address ?? undefined], [account.address]) + const nonceInputs = useMemo(() => [address ?? undefined], [address]) const tokenNonceState = useSingleCallResult(eip2612Contract, 'nonces', nonceInputs) const permitInfo = overridePermitInfo ?? - (account.status === 'connected' && tokenAddress ? PERMITTABLE_TOKENS[account.chainId]?.[tokenAddress] : undefined) + (status === 'connected' && chainId && tokenAddress ? PERMITTABLE_TOKENS[chainId]?.[tokenAddress] : undefined) const [signatureData, setSignatureData] = useState(null) @@ -133,7 +133,8 @@ export function useERC20Permit( isArgentWallet || !currencyAmount || !eip2612Contract || - account.status !== 'connected' || + !chainId || + !address || !transactionDeadline || !provider || !tokenNonceState.valid || @@ -159,7 +160,7 @@ export function useERC20Permit( const isSignatureDataValid = signatureData && - signatureData.owner === account.address && + signatureData.owner === address && signatureData.deadline >= transactionDeadline.toNumber() && signatureData.tokenAddress === tokenAddress && signatureData.nonce === nonceNumber && @@ -177,14 +178,14 @@ export function useERC20Permit( const message = allowed ? { - holder: account.address, + holder: address, spender, allowed, nonce: nonceNumber, expiry: signatureDeadline, } : { - owner: account.address, + owner: address, spender, value, nonce: nonceNumber, @@ -195,12 +196,12 @@ export function useERC20Permit( name: permitInfo.name, version: permitInfo.version, verifyingContract: tokenAddress, - chainId: account.chainId, + chainId, } : { name: permitInfo.name, verifyingContract: tokenAddress, - chainId: account.chainId, + chainId, } const data = JSON.stringify({ types: { @@ -213,7 +214,7 @@ export function useERC20Permit( }) return provider - .send('eth_signTypedData_v4', [account.address, data]) + .send('eth_signTypedData_v4', [address, data]) .then(splitSignature) .then((signature) => { setSignatureData({ @@ -223,8 +224,8 @@ export function useERC20Permit( deadline: signatureDeadline, ...(allowed ? { allowed } : { amount: value }), nonce: nonceNumber, - chainId: account.chainId, - owner: account.address, + chainId, + owner: address, spender, tokenAddress, permitType: permitInfo.type, @@ -236,9 +237,8 @@ export function useERC20Permit( isArgentWallet, currencyAmount, eip2612Contract, - account.status, - account.address, - account.chainId, + chainId, + address, transactionDeadline, provider, tokenNonceState.valid, diff --git a/apps/web/src/hooks/useEthersProvider.ts b/apps/web/src/hooks/useEthersProvider.ts index ccb40152a8e..0f1663a5ec6 100644 --- a/apps/web/src/hooks/useEthersProvider.ts +++ b/apps/web/src/hooks/useEthersProvider.ts @@ -1,23 +1,28 @@ import { Web3Provider } from '@ethersproject/providers' +import { SupportedInterfaceChain } from 'constants/chains' import { useMemo } from 'react' -import type { Chain, Client, Transport } from 'viem' -import { Config, useClient, useConnectorClient } from 'wagmi' +import type { Client, Transport } from 'viem' +import { useClient, useConnectorClient } from 'wagmi' const providers = new WeakMap() -function clientToProvider(client?: Client, chainId?: number) { - if (!client) return undefined +function clientToProvider(client?: Client, chainId?: number) { + if (!client) { + return undefined + } const { chain, transport } = client const network = chain ? { chainId: chain.id, name: chain.name, - ensAddress: chain.contracts?.ensRegistry?.address, + ensAddress: 'ensRegistry' in chain.contracts ? chain.contracts.ensRegistry.address : undefined, } : chainId ? { chainId, name: 'Unsupported' } : undefined - if (!network) return undefined + if (!network) { + return undefined + } if (providers?.has(client)) { return providers.get(client) @@ -30,13 +35,13 @@ function clientToProvider(client?: Client, chainId?: number) { /** Hook to convert a viem Client to an ethers.js Provider with a default disconnected Network fallback. */ export function useEthersProvider({ chainId }: { chainId?: number } = {}) { - const { data: client } = useConnectorClient({ chainId }) - const disconnectedClient = useClient({ chainId }) + const { data: client } = useConnectorClient({ chainId }) + const disconnectedClient = useClient({ chainId }) return useMemo(() => clientToProvider(client ?? disconnectedClient, chainId), [chainId, client, disconnectedClient]) } /** Hook to convert a connected viem Client to an ethers.js Provider. */ export function useEthersWeb3Provider({ chainId }: { chainId?: number } = {}) { - const { data: client } = useConnectorClient({ chainId }) + const { data: client } = useConnectorClient({ chainId }) return useMemo(() => clientToProvider(client, chainId), [chainId, client]) } diff --git a/apps/web/src/hooks/useEthersSigner.ts b/apps/web/src/hooks/useEthersSigner.ts index 390ed1c3c73..5c87a23676a 100644 --- a/apps/web/src/hooks/useEthersSigner.ts +++ b/apps/web/src/hooks/useEthersSigner.ts @@ -1,15 +1,18 @@ import { Web3Provider } from '@ethersproject/providers' +import { SupportedInterfaceChain } from 'constants/chains' import { useMemo } from 'react' -import type { Account, Chain, Client, Transport } from 'viem' -import { Config, useConnectorClient } from 'wagmi' +import type { Account, Client, Transport } from 'viem' +import { useConnectorClient } from 'wagmi' -function clientToSigner(client?: Client) { - if (!client || !client.chain) return undefined +function clientToSigner(client?: Client) { + if (!client || !client.chain) { + return undefined + } const { chain, transport, account } = client const network = { chainId: chain.id, name: chain.name, - ensAddress: chain.contracts?.ensRegistry?.address, + ensAddress: 'ensRegistry' in chain.contracts ? chain.contracts.ensRegistry.address : undefined, } const provider = new Web3Provider(transport, network) return provider.getSigner(account.address) @@ -19,6 +22,6 @@ function clientToSigner(client?: Client) { // TODO(wagmi migration): Remove eslinst disable when hook is used // eslint-disable-next-line import/no-unused-modules export function useEthersSigner({ chainId }: { chainId?: number } = {}) { - const { data: client } = useConnectorClient({ chainId }) + const { data: client } = useConnectorClient({ chainId }) return useMemo(() => clientToSigner(client), [client]) } diff --git a/apps/web/src/hooks/useFilterPossiblyMaliciousPositions.ts b/apps/web/src/hooks/useFilterPossiblyMaliciousPositions.ts index 7aab09e11cf..8a5530bfa3e 100644 --- a/apps/web/src/hooks/useFilterPossiblyMaliciousPositions.ts +++ b/apps/web/src/hooks/useFilterPossiblyMaliciousPositions.ts @@ -12,8 +12,8 @@ import { Token, } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' import { hasURL } from 'utils/urlChecks' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import { useTokenContractsConstant } from './useTokenContractsConstant' function getUniqueAddressesFromPositions(positions: PositionDetails[]): string[] { @@ -66,7 +66,7 @@ function getPositionCurrencyInfosQueryOptions(position: PositionDetails, chainId * The hope is that this approach removes the cheapest version of the attack without punishing non-malicious url symbols */ export function useFilterPossiblyMaliciousPositions(positions: PositionDetails[]): PositionDetails[] { - const chainId = useChainId() + const { chainId } = useAccount() const nonListPositionTokenAddresses = useMemo(() => getUniqueAddressesFromPositions(positions), [positions]) const positionCurrencyInfos = useQueries({ @@ -78,7 +78,9 @@ export function useFilterPossiblyMaliciousPositions(positions: PositionDetails[] const result: Record = {} for (let i = 0; i < nonListPositionTokenAddresses.length; i++) { const callResult = symbolCallStates[i]?.result - if (!callResult) continue + if (!callResult) { + continue + } const address = nonListPositionTokenAddresses[i] result[address] = callResult as unknown as string } @@ -88,23 +90,37 @@ export function useFilterPossiblyMaliciousPositions(positions: PositionDetails[] return useMemo(() => { return positionCurrencyInfos .map((result) => { - if (!result.data) return undefined + if (!result.data) { + return undefined + } const { currency0Info, currency1Info, position } = result.data let tokensInListCount = 0 - if (!currency0Info?.isSpam && currency0Info?.safetyLevel === SafetyLevel.Verified) tokensInListCount++ - if (!currency1Info?.isSpam && currency1Info?.safetyLevel === SafetyLevel.Verified) tokensInListCount++ + if (!currency0Info?.isSpam && currency0Info?.safetyLevel === SafetyLevel.Verified) { + tokensInListCount++ + } + if (!currency1Info?.isSpam && currency1Info?.safetyLevel === SafetyLevel.Verified) { + tokensInListCount++ + } // if both tokens are in the list, then we let both have url symbols (so we don't check) - if (tokensInListCount === 2) return position + if (tokensInListCount === 2) { + return position + } // check the token symbols to see if they contain a url // prioritize the token entity from the list if it exists // if the token isn't in the list, then use the data returned from chain calls let urlSymbolCount = 0 - if (hasURL(currency0Info?.currency?.symbol ?? addressesToSymbol[position.token0])) urlSymbolCount++ - if (hasURL(currency1Info?.currency?.symbol ?? addressesToSymbol[position.token1])) urlSymbolCount++ + if (hasURL(currency0Info?.currency?.symbol ?? addressesToSymbol[position.token0])) { + urlSymbolCount++ + } + if (hasURL(currency1Info?.currency?.symbol ?? addressesToSymbol[position.token1])) { + urlSymbolCount++ + } // if one token is in the list, then one token can have a url symbol - if (tokensInListCount === 1 && urlSymbolCount < 2) return position + if (tokensInListCount === 1 && urlSymbolCount < 2) { + return position + } // if neither token is in the list, then neither can have a url symbol return urlSymbolCount === 0 ? position : undefined diff --git a/apps/web/src/hooks/useGlobalChainSwitch.ts b/apps/web/src/hooks/useGlobalChainSwitch.ts index e55f8901007..48193f1cdc5 100644 --- a/apps/web/src/hooks/useGlobalChainSwitch.ts +++ b/apps/web/src/hooks/useGlobalChainSwitch.ts @@ -1,11 +1,11 @@ import { chainIdToBackendChain, useIsSupportedChainId } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import { useEffect } from 'react' import { useAppSelector } from 'state/hooks' import { Chain } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' -import { useChainId } from 'wagmi' export const useOnGlobalChainSwitch = (callback: (chainId: number, chain?: Chain) => void) => { - const chainId = useChainId() + const { chainId } = useAccount() const isSupportedChain = useIsSupportedChainId(chainId) const switchingChain = useAppSelector((state) => state.wallets.switchingChain) useEffect(() => { diff --git a/apps/web/src/hooks/useIsWindowVisible.ts b/apps/web/src/hooks/useIsWindowVisible.ts index b5c3d98ec41..b168d117ac0 100644 --- a/apps/web/src/hooks/useIsWindowVisible.ts +++ b/apps/web/src/hooks/useIsWindowVisible.ts @@ -18,7 +18,9 @@ export default function useIsWindowVisible(): boolean { }, [setFocused]) useEffect(() => { - if (!isVisibilityStateSupported()) return undefined + if (!isVisibilityStateSupported()) { + return undefined + } setFocused(() => isWindowVisible()) document.addEventListener('visibilitychange', listener) diff --git a/apps/web/src/hooks/useLast.ts b/apps/web/src/hooks/useLast.ts index c12d2c45907..89464d09b6c 100644 --- a/apps/web/src/hooks/useLast.ts +++ b/apps/web/src/hooks/useLast.ts @@ -10,7 +10,9 @@ export default function useLast(value: T, filterFn?: (value: T) => boolean): useEffect(() => { setLast((last) => { const shouldUse: boolean = filterFn ? filterFn(value) : true - if (shouldUse) return value + if (shouldUse) { + return value + } return last }) }, [filterFn, value]) diff --git a/apps/web/src/hooks/useLocalCurrencyLinkProps.ts b/apps/web/src/hooks/useLocalCurrencyLinkProps.ts index e1467cf3bfc..ce948a277ef 100644 --- a/apps/web/src/hooks/useLocalCurrencyLinkProps.ts +++ b/apps/web/src/hooks/useLocalCurrencyLinkProps.ts @@ -1,4 +1,3 @@ -import { sendAnalyticsEvent } from 'analytics' import { SupportedLocalCurrency } from 'constants/localCurrencies' import useParsedQueryString from 'hooks/useParsedQueryString' import { useAtom } from 'jotai' @@ -6,7 +5,8 @@ import { stringify } from 'qs' import { useMemo } from 'react' import type { To } from 'react-router-dom' import { useLocation } from 'react-router-dom' - +import { InterfaceEventNameLocal } from 'uniswap/src/features/telemetry/constants' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { activeLocalCurrencyAtom, useActiveLocalCurrency } from './useActiveLocalCurrency' export function useLocalCurrencyLinkProps(localCurrency?: SupportedLocalCurrency): { @@ -29,7 +29,7 @@ export function useLocalCurrencyLinkProps(localCurrency?: SupportedLocalCurrency }, onClick: () => { updateActiveLocalCurrency(localCurrency) - sendAnalyticsEvent('Local Currency Selected', { + sendAnalyticsEvent(InterfaceEventNameLocal.LocalCurrencySelected, { previous_local_currency: activeLocalCurrency, new_local_currency: localCurrency, }) diff --git a/apps/web/src/hooks/useNetworkSupportsV2.ts b/apps/web/src/hooks/useNetworkSupportsV2.ts index 16b1e775861..8a3cbcf1ea6 100644 --- a/apps/web/src/hooks/useNetworkSupportsV2.ts +++ b/apps/web/src/hooks/useNetworkSupportsV2.ts @@ -1,15 +1,11 @@ -import { SUPPORTED_V2POOL_CHAIN_IDS, SUPPORTED_V2POOL_CHAIN_IDS_DEPRECATED } from 'constants/chains' +import { SUPPORTED_V2POOL_CHAIN_IDS } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import { FeatureFlags } from 'uniswap/src/features/gating/flags' import { useFeatureFlag } from 'uniswap/src/features/gating/hooks' -import { useAccount } from 'wagmi' export function useNetworkSupportsV2() { const { chainId } = useAccount() const isV2EverywhereEnabled = useFeatureFlag(FeatureFlags.V2Everywhere) - return ( - chainId && - ((isV2EverywhereEnabled && SUPPORTED_V2POOL_CHAIN_IDS.includes(chainId)) || - SUPPORTED_V2POOL_CHAIN_IDS_DEPRECATED.includes(chainId)) - ) + return chainId && isV2EverywhereEnabled && SUPPORTED_V2POOL_CHAIN_IDS.includes(chainId) } diff --git a/apps/web/src/hooks/useOnClickOutside.ts b/apps/web/src/hooks/useOnClickOutside.ts index af9f08a4fab..2a0f2d39a99 100644 --- a/apps/web/src/hooks/useOnClickOutside.ts +++ b/apps/web/src/hooks/useOnClickOutside.ts @@ -23,7 +23,9 @@ export function useOnClickOutside( return } - if (handlerRef.current) handlerRef.current() + if (handlerRef.current) { + handlerRef.current() + } } document.addEventListener('mousedown', handleClickOutside) diff --git a/apps/web/src/hooks/usePermit2Allowance.ts b/apps/web/src/hooks/usePermit2Allowance.ts index 0e88ea7463a..b01809593e1 100644 --- a/apps/web/src/hooks/usePermit2Allowance.ts +++ b/apps/web/src/hooks/usePermit2Allowance.ts @@ -56,7 +56,9 @@ export default function usePermit2Allowance( const updateTokenAllowance = useUpdateTokenAllowance(amount, PERMIT2_ADDRESS) const revokeTokenAllowance = useRevokeTokenAllowance(token, PERMIT2_ADDRESS) const isApproved = useMemo(() => { - if (!amount || !tokenAllowance) return false + if (!amount || !tokenAllowance) { + return false + } return tokenAllowance.greaterThan(amount) || tokenAllowance.equalTo(amount) }, [amount, tokenAllowance]) @@ -93,14 +95,18 @@ export default function usePermit2Allowance( const [signature, setSignature] = useState() const isSigned = useMemo(() => { - if (!amount || !signature) return false + if (!amount || !signature) { + return false + } return signature.details.token === token?.address && signature.spender === spender && signature.sigDeadline >= now }, [amount, now, signature, spender, token?.address]) const { permitAllowance, expiration: permitExpiration, nonce } = usePermitAllowance(token, account, spender) const updatePermitAllowance = useUpdatePermitAllowance(token, spender, nonce, setSignature) const isPermitted = useMemo(() => { - if (!amount || !permitAllowance || !permitExpiration) return false + if (!amount || !permitAllowance || !permitExpiration) { + return false + } return (permitAllowance.greaterThan(amount) || permitAllowance.equalTo(amount)) && permitExpiration >= now }, [amount, now, permitAllowance, permitExpiration]) diff --git a/apps/web/src/hooks/usePermitAllowance.ts b/apps/web/src/hooks/usePermitAllowance.ts index 12e567d18ae..278b2c2fbd2 100644 --- a/apps/web/src/hooks/usePermitAllowance.ts +++ b/apps/web/src/hooks/usePermitAllowance.ts @@ -1,5 +1,6 @@ import { AllowanceTransfer, MaxAllowanceTransferAmount, PERMIT2_ADDRESS, PermitSingle } from '@uniswap/permit2-sdk' import { CurrencyAmount, Token } from '@uniswap/sdk-core' +import { useAccount } from 'hooks/useAccount' import { useContract } from 'hooks/useContract' import { useEthersSigner } from 'hooks/useEthersSigner' import { useSingleCallResult } from 'lib/hooks/multicall' @@ -11,7 +12,6 @@ import { Permit2 } from 'uniswap/src/abis/types' import { UserRejectedRequestError, toReadableError } from 'utils/errors' import { signTypedData } from 'utils/signing' import { didUserReject } from 'utils/swapErrorToUserReadableMessage' -import { useAccount } from 'wagmi' const PERMIT_EXPIRATION = ms(`30d`) const PERMIT_SIG_EXPIRATION = ms(`30m`) @@ -64,11 +64,24 @@ export function useUpdatePermitAllowance( () => trace({ name: 'Permit2', op: 'permit.permit2.signature' }, async (trace) => { try { - if (account.status !== 'connected') throw new Error('wallet not connected') - if (!signer) throw new Error('missing signer') - if (!token) throw new Error('missing token') - if (!spender) throw new Error('missing spender') - if (nonce === undefined) throw new Error('missing nonce') + if (account.status !== 'connected') { + throw new Error('wallet not connected') + } + if (!account.chainId) { + throw new Error('connected to an unsupported network') + } + if (!signer) { + throw new Error('missing signer') + } + if (!token) { + throw new Error('missing token') + } + if (!spender) { + throw new Error('missing spender') + } + if (nonce === undefined) { + throw new Error('missing nonce') + } const permit: Permit = { details: { diff --git a/apps/web/src/hooks/usePools.ts b/apps/web/src/hooks/usePools.ts index 626afaf118f..ab1f0f78ece 100644 --- a/apps/web/src/hooks/usePools.ts +++ b/apps/web/src/hooks/usePools.ts @@ -3,12 +3,12 @@ import { BigintIsh, ChainId, Currency, Token, V3_CORE_FACTORY_ADDRESSES } from ' import IUniswapV3PoolStateJSON from '@uniswap/v3-core/artifacts/contracts/interfaces/pool/IUniswapV3PoolState.sol/IUniswapV3PoolState.json' import { FeeAmount, Pool, computePoolAddress } from '@uniswap/v3-sdk' import { useContractMultichain } from 'components/AccountDrawer/MiniPortfolio/Pools/hooks' +import { useAccount } from 'hooks/useAccount' import JSBI from 'jsbi' import { useMultipleContractSingleData } from 'lib/hooks/multicall' import { useEffect, useMemo, useRef } from 'react' import { IUniswapV3PoolStateInterface } from 'uniswap/src/abis/types/v3/IUniswapV3PoolState' import { UniswapV3Pool } from 'uniswap/src/abis/types/v3/UniswapV3Pool' -import { useChainId } from 'wagmi' const POOL_STATE_INTERFACE = new Interface(IUniswapV3PoolStateJSON.abi) as IUniswapV3PoolStateInterface @@ -31,7 +31,9 @@ class PoolCache { const { address: addressB } = tokenB const key = `${factoryAddress}:${addressA}:${addressB}:${fee.toString()}` const found = this.addresses.find((address) => address.key === key) - if (found) return found.address + if (found) { + return found.address + } const address = { key, @@ -67,7 +69,9 @@ class PoolCache { JSBI.EQ(pool.liquidity, liquidity) && pool.tickCurrent === tick ) - if (found) return found + if (found) { + return found + } const pool = new Pool(tokenA, tokenB, fee, sqrtPriceX96, liquidity, tick) this.pools.unshift(pool) @@ -85,16 +89,20 @@ export enum PoolState { export function usePools( poolKeys: [Currency | undefined, Currency | undefined, FeeAmount | undefined][] ): [PoolState, Pool | null][] { - const chainId = useChainId() + const { chainId } = useAccount() const poolTokens: ([Token, Token, FeeAmount] | undefined)[] = useMemo(() => { - if (!chainId) return new Array(poolKeys.length) + if (!chainId) { + return new Array(poolKeys.length) + } return poolKeys.map(([currencyA, currencyB, feeAmount]) => { if (currencyA && currencyB && feeAmount) { const tokenA = currencyA.wrapped const tokenB = currencyB.wrapped - if (tokenA.equals(tokenB)) return undefined + if (tokenA.equals(tokenB)) { + return undefined + } return tokenA.sortsBefore(tokenB) ? [tokenA, tokenB, feeAmount] : [tokenB, tokenA, feeAmount] } @@ -104,7 +112,9 @@ export function usePools( const poolAddresses: (string | undefined)[] = useMemo(() => { const v3CoreFactoryAddress = chainId && V3_CORE_FACTORY_ADDRESSES[chainId] - if (!v3CoreFactoryAddress) return new Array(poolTokens.length) + if (!v3CoreFactoryAddress) { + return new Array(poolTokens.length) + } return poolTokens.map((value) => value && PoolCache.getPoolAddress(v3CoreFactoryAddress, ...value)) }, [chainId, poolTokens]) @@ -115,19 +125,33 @@ export function usePools( return useMemo(() => { return poolKeys.map((_key, index) => { const tokens = poolTokens[index] - if (!tokens) return [PoolState.INVALID, null] + if (!tokens) { + return [PoolState.INVALID, null] + } const [token0, token1, fee] = tokens - if (!slot0s[index]) return [PoolState.INVALID, null] + if (!slot0s[index]) { + return [PoolState.INVALID, null] + } const { result: slot0, loading: slot0Loading, valid: slot0Valid } = slot0s[index] - if (!liquidities[index]) return [PoolState.INVALID, null] + if (!liquidities[index]) { + return [PoolState.INVALID, null] + } const { result: liquidity, loading: liquidityLoading, valid: liquidityValid } = liquidities[index] - if (!tokens || !slot0Valid || !liquidityValid) return [PoolState.INVALID, null] - if (slot0Loading || liquidityLoading) return [PoolState.LOADING, null] - if (!slot0 || !liquidity) return [PoolState.NOT_EXISTS, null] - if (!slot0.sqrtPriceX96 || slot0.sqrtPriceX96.eq(0)) return [PoolState.NOT_EXISTS, null] + if (!tokens || !slot0Valid || !liquidityValid) { + return [PoolState.INVALID, null] + } + if (slot0Loading || liquidityLoading) { + return [PoolState.LOADING, null] + } + if (!slot0 || !liquidity) { + return [PoolState.NOT_EXISTS, null] + } + if (!slot0.sqrtPriceX96 || slot0.sqrtPriceX96.eq(0)) { + return [PoolState.NOT_EXISTS, null] + } try { const pool = PoolCache.getPool(token0, token1, fee, slot0.sqrtPriceX96, liquidity[0], slot0.tick) diff --git a/apps/web/src/hooks/usePositionTokenURI.ts b/apps/web/src/hooks/usePositionTokenURI.ts index 4056d88c876..7d5b0d6f13f 100644 --- a/apps/web/src/hooks/usePositionTokenURI.ts +++ b/apps/web/src/hooks/usePositionTokenURI.ts @@ -59,11 +59,12 @@ export function usePositionTokenURI(tokenId: TokenId | undefined): UsePositionTo } } const [tokenURI] = result as [string] - if (!tokenURI || !tokenURI.startsWith(STARTS_WITH)) + if (!tokenURI || !tokenURI.startsWith(STARTS_WITH)) { return { valid: false, loading: false, } + } try { const json = JSON.parse(atob(tokenURI.slice(STARTS_WITH.length))) diff --git a/apps/web/src/hooks/useSendCallback.ts b/apps/web/src/hooks/useSendCallback.ts index f91f0a8a206..104fc45a3db 100644 --- a/apps/web/src/hooks/useSendCallback.ts +++ b/apps/web/src/hooks/useSendCallback.ts @@ -1,5 +1,6 @@ import { TransactionRequest } from '@ethersproject/abstract-provider' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' +import { useAccount } from 'hooks/useAccount' import { useEthersSigner } from 'hooks/useEthersSigner' import { GasFeeResult } from 'hooks/useTransactionGasFee' import { useCallback } from 'react' @@ -9,7 +10,6 @@ import { trace } from 'tracing/trace' import { currencyId } from 'utils/currencyId' import { UserRejectedRequestError, toReadableError } from 'utils/errors' import { didUserReject } from 'utils/swapErrorToUserReadableMessage' -import { useAccount } from 'wagmi' export function useSendCallback({ currencyAmount, @@ -29,11 +29,21 @@ export function useSendCallback({ return useCallback( () => trace({ name: 'Send', op: 'send' }, async (trace) => { - if (account.status !== 'connected') throw new Error('wallet must be connected to send') - if (!signer) throw new Error('missing signer') - if (!transactionRequest) throw new Error('missing to transaction to execute') - if (!currencyAmount) throw new Error('missing currency amount to send') - if (!recipient) throw new Error('missing recipient') + if (account.status !== 'connected') { + throw new Error('wallet must be connected to send') + } + if (!signer) { + throw new Error('missing signer') + } + if (!transactionRequest) { + throw new Error('missing to transaction to execute') + } + if (!currencyAmount) { + throw new Error('missing currency amount to send') + } + if (!recipient) { + throw new Error('missing recipient') + } try { const response = await trace.child( diff --git a/apps/web/src/hooks/useStablecoinPrice.ts b/apps/web/src/hooks/useStablecoinPrice.ts index 558ea3f5a3b..ae838c61a67 100644 --- a/apps/web/src/hooks/useStablecoinPrice.ts +++ b/apps/web/src/hooks/useStablecoinPrice.ts @@ -1,10 +1,10 @@ import { Currency, CurrencyAmount, Price, Token, TradeType } from '@uniswap/sdk-core' -import { getChainInfo, useSupportedChainId } from 'constants/chains' +import { getChain, useSupportedChainId } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { useMemo, useRef } from 'react' import { ClassicTrade, INTERNAL_ROUTER_PREFERENCE_PRICE } from 'state/routing/types' import { useRoutingAPITrade } from 'state/routing/useRoutingAPITrade' -import { useChainId } from 'wagmi' /** * Returns the price in USDC of the input currency @@ -12,7 +12,7 @@ import { useChainId } from 'wagmi' */ export default function useStablecoinPrice(currency?: Currency): Price | undefined { const chainId = useSupportedChainId(currency?.chainId) - const amountOut = chainId ? getChainInfo({ chainId }).spotPriceStablecoinAmount : undefined + const amountOut = chainId ? getChain({ chainId }).spotPriceStablecoinAmount : undefined const stablecoin = amountOut?.currency const { trade } = useRoutingAPITrade( @@ -57,7 +57,9 @@ export function useStablecoinValue(currencyAmount: CurrencyAmount | un const price = useStablecoinPrice(currencyAmount?.currency) return useMemo(() => { - if (!price || !currencyAmount) return null + if (!price || !currencyAmount) { + return null + } try { return price.quote(currencyAmount) } catch (error) { @@ -72,10 +74,10 @@ export function useStablecoinValue(currencyAmount: CurrencyAmount | un * @returns CurrencyAmount where currency is stablecoin on active chain */ export function useStablecoinAmountFromFiatValue(fiatValue: number | null | undefined) { - const chainId = useChainId() + const { chainId } = useAccount() const supportedChainId = useSupportedChainId(chainId) const stablecoin = supportedChainId - ? getChainInfo({ chainId: supportedChainId }).spotPriceStablecoinAmount.currency + ? getChain({ chainId: supportedChainId }).spotPriceStablecoinAmount.currency : undefined return useMemo(() => { diff --git a/apps/web/src/hooks/useSwapCallback.tsx b/apps/web/src/hooks/useSwapCallback.tsx index 66550c4fa80..75f64da1316 100644 --- a/apps/web/src/hooks/useSwapCallback.tsx +++ b/apps/web/src/hooks/useSwapCallback.tsx @@ -25,8 +25,12 @@ export type SwapResult = Awaited>> type UniversalRouterFeeField = { feeOptions: FeeOptions } | { flatFeeOptions: FlatFeeOptions } function getUniversalRouterFeeFields(trade?: InterfaceTrade): UniversalRouterFeeField | undefined { - if (!isClassicTrade(trade)) return undefined - if (!trade.swapFee) return undefined + if (!isClassicTrade(trade)) { + return undefined + } + if (!trade.swapFee) { + return undefined + } if (trade.tradeType === TradeType.EXACT_INPUT) { return { feeOptions: { fee: trade.swapFee.percent, recipient: trade.swapFee.recipient } } @@ -66,8 +70,12 @@ export function useSwapCallback( const swapCallback = isUniswapXTrade(trade) ? uniswapXSwapCallback : universalRouterSwapCallback return useCallback(async () => { - if (!trade) throw new Error('missing trade') - if (!account || !chainId) throw new Error('wallet must be connected to swap') + if (!trade) { + throw new Error('missing trade') + } + if (!account || !chainId) { + throw new Error('wallet must be connected to swap') + } const result = await swapCallback() diff --git a/apps/web/src/hooks/useSwapTaxes.ts b/apps/web/src/hooks/useSwapTaxes.ts index 7189528b69b..1adf7a416cd 100644 --- a/apps/web/src/hooks/useSwapTaxes.ts +++ b/apps/web/src/hooks/useSwapTaxes.ts @@ -2,13 +2,12 @@ import { InterfaceEventName } from '@uniswap/analytics-events' import { ChainId, Percent } from '@uniswap/sdk-core' import { WETH_ADDRESS as getWethAddress } from '@uniswap/universal-router-sdk' import { useWeb3React } from '@web3-react/core' -import { sendAnalyticsEvent } from 'analytics' +import { BIPS_BASE, ZERO_PERCENT } from 'constants/misc' +import { useAccount } from 'hooks/useAccount' import { useEffect, useState } from 'react' import FOT_DETECTOR_ABI from 'uniswap/src/abis/fee-on-transfer-detector.json' import { FeeOnTransferDetector } from 'uniswap/src/abis/types' -import { useChainId } from 'wagmi' - -import { BIPS_BASE, ZERO_PERCENT } from 'constants/misc' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { useContract } from './useContract' // TODO(WEB-4058): Move all of these contract addresses into the top-level wagmi config @@ -97,10 +96,12 @@ async function getSwapTaxes( export function useSwapTaxes(inputTokenAddress?: string, outputTokenAddress?: string) { const fotDetector = useFeeOnTransferDetectorContract() const [{ inputTax, outputTax }, setTaxes] = useState({ inputTax: ZERO_PERCENT, outputTax: ZERO_PERCENT }) - const chainId = useChainId() + const { chainId } = useAccount() useEffect(() => { - if (!fotDetector || !chainId) return + if (!fotDetector || !chainId) { + return + } getSwapTaxes(fotDetector, inputTokenAddress, outputTokenAddress, chainId).then(setTaxes) }, [fotDetector, inputTokenAddress, outputTokenAddress, chainId]) diff --git a/apps/web/src/hooks/useSwitchChain.ts b/apps/web/src/hooks/useSwitchChain.ts index c535b27d1cc..67a82a511a6 100644 --- a/apps/web/src/hooks/useSwitchChain.ts +++ b/apps/web/src/hooks/useSwitchChain.ts @@ -1,11 +1,11 @@ import { ChainId } from '@uniswap/sdk-core' import { CHAIN_IDS_TO_NAMES, useIsSupportedChainIdCallback } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import { useCallback } from 'react' import { useAppDispatch } from 'state/hooks' import { endSwitchingChain, startSwitchingChain } from 'state/wallets/reducer' import { trace } from 'tracing/trace' - -import { useAccount, useSwitchChain as useSwitchChainWagmi } from 'wagmi' +import { useSwitchChain as useSwitchChainWagmi } from 'wagmi' export function useSwitchChain() { const dispatch = useAppDispatch() diff --git a/apps/web/src/hooks/useSyncChainQuery.ts b/apps/web/src/hooks/useSyncChainQuery.ts index b70b0ffbeed..16a4cb18f43 100644 --- a/apps/web/src/hooks/useSyncChainQuery.ts +++ b/apps/web/src/hooks/useSyncChainQuery.ts @@ -1,10 +1,10 @@ import { useWeb3React } from '@web3-react/core' import { CHAIN_IDS_TO_NAMES, useIsSupportedChainId } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import { ParsedQs } from 'qs' import { useEffect, useRef } from 'react' import { useSearchParams } from 'react-router-dom' -import { useAccount } from 'wagmi' import useParsedQueryString from './useParsedQueryString' import useSelectChain from './useSelectChain' @@ -16,7 +16,9 @@ function getChainIdFromName(name: string) { export function getParsedChainId(parsedQs?: ParsedQs) { const chain = parsedQs?.chain - if (!chain || typeof chain !== 'string') return + if (!chain || typeof chain !== 'string') { + return + } return getChainIdFromName(chain) } @@ -44,7 +46,7 @@ export default function useSyncChainQuery() { const [searchParams, setSearchParams] = useSearchParams() useEffect(() => { - // Change a page chain on pageload if the app chainId does not match the query param chain + // Change page chain on pageload if the app chainId does not match the query param chain if (urlChainId && chainIdRef.current === chainId && chainId !== urlChainId) { selectChain(urlChainId) } @@ -57,6 +59,9 @@ export default function useSyncChainQuery() { searchParams.delete('chain') setSearchParams(searchParams, { replace: true }) } + searchParams.delete('inputCurrency') + searchParams.delete('outputCurrency') + setSearchParams(searchParams, { replace: true }) } // If a user has a connected wallet and the chainId matches the query param chain, update the chainIdRef else if (isConnected && chainId === urlChainId) { diff --git a/apps/web/src/hooks/useTokenAllowance.ts b/apps/web/src/hooks/useTokenAllowance.ts index f04d7417150..98de6311040 100644 --- a/apps/web/src/hooks/useTokenAllowance.ts +++ b/apps/web/src/hooks/useTokenAllowance.ts @@ -1,12 +1,13 @@ import { ContractTransaction } from '@ethersproject/contracts' import { InterfaceEventName } from '@uniswap/analytics-events' import { CurrencyAmount, MaxUint256, Token } from '@uniswap/sdk-core' -import { sendAnalyticsEvent, useTrace as useAnalyticsTrace } from 'analytics' import { useTokenContract } from 'hooks/useContract' import { useSingleCallResult } from 'lib/hooks/multicall' import { useCallback, useEffect, useMemo, useState } from 'react' import { ApproveTransactionInfo, TransactionType } from 'state/transactions/types' import { trace } from 'tracing/trace' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { UserRejectedRequestError } from 'utils/errors' import { didUserReject } from 'utils/swapErrorToUserReadableMessage' @@ -46,15 +47,21 @@ export function useUpdateTokenAllowance( spender: string ): () => Promise<{ response: ContractTransaction; info: ApproveTransactionInfo }> { const contract = useTokenContract(amount?.currency.address) - const analyticsTrace = useAnalyticsTrace() + const analyticsTrace = useTrace() return useCallback( () => trace({ name: 'Allowance', op: 'permit.allowance' }, async (trace) => { try { - if (!amount) throw new Error('missing amount') - if (!contract) throw new Error('missing contract') - if (!spender) throw new Error('missing spender') + if (!amount) { + throw new Error('missing amount') + } + if (!contract) { + throw new Error('missing contract') + } + if (!spender) { + throw new Error('missing spender') + } const allowance = amount.equalTo(0) ? '0' : MAX_ALLOWANCE const response = await trace.child({ name: 'Approve', op: 'wallet.approve' }, async (walletTrace) => { diff --git a/apps/web/src/hooks/useTokenBalances.ts b/apps/web/src/hooks/useTokenBalances.ts index e8b2bddeae5..596fe33ad39 100644 --- a/apps/web/src/hooks/useTokenBalances.ts +++ b/apps/web/src/hooks/useTokenBalances.ts @@ -1,16 +1,16 @@ import { useTokenBalancesQuery } from 'graphql/data/apollo/TokenBalancesProvider' import { supportedChainIdFromGQLChain } from 'graphql/data/util' +import { useAccount } from 'hooks/useAccount' import { TokenBalances } from 'lib/hooks/useTokenList/sorting' import { useMemo } from 'react' import { PortfolioTokenBalancePartsFragment } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' -import { useChainId } from 'wagmi' export function useTokenBalances(): { balanceMap: TokenBalances balanceList: readonly (PortfolioTokenBalancePartsFragment | undefined)[] loading: boolean } { - const chainId = useChainId() + const { chainId } = useAccount() const { data, loading } = useTokenBalancesQuery() return useMemo(() => { const balanceList = data?.portfolios?.[0]?.tokenBalances ?? [] @@ -23,12 +23,11 @@ export function useTokenBalances(): { if ( tokenBalance?.token?.chain && supportedChainIdFromGQLChain(tokenBalance.token?.chain) === chainId && - address && - tokenBalance.denominatedValue?.value !== undefined + address ) { - const usdValue = tokenBalance.denominatedValue?.value - const balance = tokenBalance.quantity - balanceMap[address] = { usdValue, balance: balance ?? 0 } + const usdValue = tokenBalance.denominatedValue?.value ?? 0 + const balance = tokenBalance.quantity ?? 0 + balanceMap[address] = { usdValue, balance } } return balanceMap }, {} as TokenBalances) ?? {} diff --git a/apps/web/src/hooks/useTransactionDeadline.ts b/apps/web/src/hooks/useTransactionDeadline.ts index f92d410e2b1..c3c61bd9dfd 100644 --- a/apps/web/src/hooks/useTransactionDeadline.ts +++ b/apps/web/src/hooks/useTransactionDeadline.ts @@ -1,15 +1,15 @@ import { BigNumber } from '@ethersproject/bignumber' import { L2_CHAIN_IDS } from 'constants/chains' import { L2_DEADLINE_FROM_NOW } from 'constants/misc' +import { useAccount } from 'hooks/useAccount' import { useInterfaceMulticall } from 'hooks/useContract' import { useCallback, useMemo } from 'react' import { useAppSelector } from 'state/hooks' -import { useChainId } from 'wagmi' import useCurrentBlockTimestamp from './useCurrentBlockTimestamp' export default function useTransactionDeadline(): BigNumber | undefined { - const chainId = useChainId() + const { chainId } = useAccount() const ttl = useAppSelector((state) => state.user.userDeadline) const blockTimestamp = useCurrentBlockTimestamp() return useMemo(() => timestampToDeadline(chainId, blockTimestamp, ttl), [blockTimestamp, chainId, ttl]) @@ -20,7 +20,7 @@ export default function useTransactionDeadline(): BigNumber | undefined { * Should be used for any submitted transactions, as it uses an on-chain timestamp instead of a client timestamp. */ export function useGetTransactionDeadline(): () => Promise { - const chainId = useChainId() + const { chainId } = useAccount() const ttl = useAppSelector((state) => state.user.userDeadline) const multicall = useInterfaceMulticall() return useCallback(async () => { @@ -30,7 +30,11 @@ export function useGetTransactionDeadline(): () => Promise trace({ name: 'Swap (Dutch)', op: 'swap.x.dutch' }, async (trace) => { - if (account.status !== 'connected') throw new Error('wallet not connected') - if (!provider) throw new Error('missing provider') - if (!trade) throw new Error('missing trade') + if (account.status !== 'connected') { + throw new Error('wallet not connected') + } + if (!provider) { + throw new Error('missing provider') + } + if (!trade) { + throw new Error('missing trade') + } - sendAnalyticsEvent('UniswapX Signature Requested', { + sendAnalyticsEvent(InterfaceEventNameLocal.UniswapXSignatureRequested, { ...formatSwapSignedAnalyticsEventProperties({ trade, allowedSlippage, @@ -184,6 +191,7 @@ export function useUniswapXSwapCallback({ tokenInChainId: updatedOrder.chainId, tokenOutChainId: updatedOrder.chainId, requestId: trade.requestId, + forceOpenOrder: trade.forceOpenOrder, } } else { endpoint = trade.offchainOrderType === OffchainOrderType.LIMIT_ORDER ? 'limit-order' : 'order' @@ -205,7 +213,7 @@ export function useUniswapXSwapCallback({ // TODO(UniswapX): For now, `errorCode` is not always present in the response, so we have to fallback // check for status code and perform this type narrowing. if (isErrorResponse(res, responseBody)) { - sendAnalyticsEvent('UniswapX Order Post Error', { + sendAnalyticsEvent(InterfaceEventNameLocal.UniswapXOrderPostError, { ...formatSwapSignedAnalyticsEventProperties({ trade, allowedSlippage, @@ -226,7 +234,7 @@ export function useUniswapXSwapCallback({ // backend team provides a list of error codes and potential messages throw new Error(`${responseBody.errorCode ?? responseBody.detail ?? 'Unknown error'}`) } - sendAnalyticsEvent('UniswapX Order Submitted', { + sendAnalyticsEvent(InterfaceEventNameLocal.UniswapXOrderSubmitted, { ...formatSwapSignedAnalyticsEventProperties({ trade, allowedSlippage, diff --git a/apps/web/src/hooks/useUniversalRouter.ts b/apps/web/src/hooks/useUniversalRouter.ts index 60c2ace755e..53ca6a89f5d 100644 --- a/apps/web/src/hooks/useUniversalRouter.ts +++ b/apps/web/src/hooks/useUniversalRouter.ts @@ -4,8 +4,8 @@ import { CustomUserProperties, SwapEventName } from '@uniswap/analytics-events' import { Percent } from '@uniswap/sdk-core' import { FlatFeeOptions, SwapRouter, UNIVERSAL_ROUTER_ADDRESS } from '@uniswap/universal-router-sdk' import { FeeOptions, toHex } from '@uniswap/v3-sdk' -import { sendAnalyticsEvent, useTrace } from 'analytics' import { useTotalBalancesUsdForAnalytics } from 'graphql/data/apollo/TokenBalancesProvider' +import { useAccount } from 'hooks/useAccount' import { useEthersWeb3Provider } from 'hooks/useEthersProvider' import { useGetTransactionDeadline } from 'hooks/useTransactionDeadline' import { t } from 'i18n' @@ -15,18 +15,19 @@ import { useCallback } from 'react' import { ClassicTrade, TradeFillType } from 'state/routing/types' import { useUserSlippageTolerance } from 'state/user/hooks' import { trace } from 'tracing/trace' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { calculateGasMargin } from 'utils/calculateGasMargin' import { UserRejectedRequestError, WrongChainError } from 'utils/errors' import isZero from 'utils/isZero' import { didUserReject, swapErrorToUserReadableMessage } from 'utils/swapErrorToUserReadableMessage' import { getWalletMeta } from 'utils/walletMeta' -import { useAccount } from 'wagmi' import { PermitSignature } from './usePermitAllowance' /** Thrown when gas estimation fails. This class of error usually requires an emulator to determine the root cause. */ class GasEstimationError extends Error { constructor() { - super(t`Your swap is expected to fail.`) + super(t('swap.error.expectedToFail')) } } @@ -36,9 +37,7 @@ class GasEstimationError extends Error { */ class ModifiedSwapError extends Error { constructor() { - super( - t`Your swap was modified through your wallet. If this was a mistake, please cancel immediately or risk losing your funds.` - ) + super(t('swap.error.modifiedByWallet')) } } @@ -68,11 +67,19 @@ export function useUniversalRouterSwapCallback( (): Promise<{ type: TradeFillType.Classic; response: TransactionResponse; deadline?: BigNumber }> => trace({ name: 'Swap (Classic)', op: 'swap.classic' }, async (trace) => { try { - if (account.status !== 'connected') throw new Error('wallet not connected') - if (!provider) throw new Error('missing provider') - if (!trade) throw new Error('missing trade') + if (account.status !== 'connected') { + throw new Error('wallet not connected') + } + if (!provider) { + throw new Error('missing provider') + } + if (!trade) { + throw new Error('missing trade') + } const connectedChainId = await provider.getSigner().getChainId() - if (account.chainId !== connectedChainId) throw new WrongChainError() + if (account.chainId !== connectedChainId) { + throw new WrongChainError() + } const deadline = await getDeadline() @@ -102,7 +109,7 @@ export function useUniversalRouterSwapCallback( ...formatCommonPropertiesForTrade(trade, options.slippageTolerance), ...analyticsContext, client_block_number: blockNumber, - tx, + txRequest: tx, isAutoSlippage, }) console.warn(gasError) diff --git a/apps/web/src/hooks/useUnmountingAnimation.ts b/apps/web/src/hooks/useUnmountingAnimation.ts index fbe3a732a58..22ff6b1cb52 100644 --- a/apps/web/src/hooks/useUnmountingAnimation.ts +++ b/apps/web/src/hooks/useUnmountingAnimation.ts @@ -39,7 +39,9 @@ export function useUnmountingAnimation( const removeChild = parent?.removeChild // If we can't remove the child or skipping is requested, stop here. - if (!(parent && removeChild) || skip) return + if (!(parent && removeChild) || skip) { + return + } // Override the parent's removeChild function to add our animation logic parent.removeChild = function (child: T) { diff --git a/apps/web/src/hooks/useV2Pairs.ts b/apps/web/src/hooks/useV2Pairs.ts index 6445a3daf5c..e90e3dfb5f8 100644 --- a/apps/web/src/hooks/useV2Pairs.ts +++ b/apps/web/src/hooks/useV2Pairs.ts @@ -42,9 +42,15 @@ export function useV2Pairs(currencies: [Currency | undefined, Currency | undefin const tokenA = tokens[i][0] const tokenB = tokens[i][1] - if (loading) return [PairState.LOADING, null] - if (!tokenA || !tokenB || tokenA.equals(tokenB)) return [PairState.INVALID, null] - if (!reserves) return [PairState.NOT_EXISTS, null] + if (loading) { + return [PairState.LOADING, null] + } + if (!tokenA || !tokenB || tokenA.equals(tokenB)) { + return [PairState.INVALID, null] + } + if (!reserves) { + return [PairState.NOT_EXISTS, null] + } const { reserve0, reserve1 } = reserves const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA] return [ diff --git a/apps/web/src/hooks/useWrapCallback.tsx b/apps/web/src/hooks/useWrapCallback.tsx index 417b2fa510d..4d9bad0263f 100644 --- a/apps/web/src/hooks/useWrapCallback.tsx +++ b/apps/web/src/hooks/useWrapCallback.tsx @@ -1,27 +1,21 @@ import { InterfaceEventName } from '@uniswap/analytics-events' import { Currency } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' -import { sendAnalyticsEvent } from 'analytics' +import { useAccount } from 'hooks/useAccount' import { Trans } from 'i18n' import useNativeCurrency from 'lib/hooks/useNativeCurrency' import { formatToDecimal, getTokenAddress } from 'lib/utils/analytics' import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { useMemo, useState } from 'react' import { trace } from 'tracing/trace' -import { useChainId } from 'wagmi' - +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { WrapType } from 'uniswap/src/types/wrap' import { WRAPPED_NATIVE_CURRENCY } from '../constants/tokens' import { useCurrencyBalance } from '../state/connection/hooks' import { useTransactionAdder } from '../state/transactions/hooks' import { TransactionType } from '../state/transactions/types' import { useWETHContract } from './useContract' -export enum WrapType { - NOT_APPLICABLE, - WRAP, - UNWRAP, -} - const NOT_APPLICABLE = { wrapType: WrapType.NOT_APPLICABLE } enum WrapInputError { @@ -33,7 +27,7 @@ enum WrapInputError { } export function WrapErrorText({ wrapInputError }: { wrapInputError: WrapInputError }) { - const chainId = useChainId() + const { chainId } = useAccount() const native = useNativeCurrency(chainId) const wrapped = native?.wrapped @@ -41,14 +35,14 @@ export function WrapErrorText({ wrapInputError }: { wrapInputError: WrapInputErr case WrapInputError.NO_ERROR: return null case WrapInputError.ENTER_NATIVE_AMOUNT: - return Enter {{ sym: native?.symbol }} amount + return case WrapInputError.ENTER_WRAPPED_AMOUNT: - return Enter {{ sym: wrapped?.symbol }} amount + return case WrapInputError.INSUFFICIENT_NATIVE_BALANCE: - return Insufficient {{ sym: native?.symbol }} balance + return case WrapInputError.INSUFFICIENT_WRAPPED_BALANCE: - return Insufficient {{ sym: wrapped?.symbol }} balance + return } } @@ -76,12 +70,18 @@ export default function useWrapCallback( // This allows an async error to propagate within the React lifecycle. // Without rethrowing it here, it would not show up in the UI - only the dev console. const [error, setError] = useState() - if (error) throw error + if (error) { + throw error + } return useMemo(() => { - if (!wethContract || !chainId || !inputCurrency || !outputCurrency) return NOT_APPLICABLE + if (!wethContract || !chainId || !inputCurrency || !outputCurrency) { + return NOT_APPLICABLE + } const weth = WRAPPED_NATIVE_CURRENCY[chainId] - if (!weth) return NOT_APPLICABLE + if (!weth) { + return NOT_APPLICABLE + } const hasInputAmount = Boolean(inputAmount?.greaterThan('0')) const sufficientBalance = inputAmount && balance && !balance.lessThan(inputAmount) diff --git a/apps/web/src/i18n.tsx b/apps/web/src/i18n.tsx index e9bf4ba1ff7..219ceff796b 100644 --- a/apps/web/src/i18n.tsx +++ b/apps/web/src/i18n.tsx @@ -1,54 +1,29 @@ -import { useEffect } from 'react' +import enUsLocale from './i18n/locales/source/en-US.json' -import { initialLocale, useActiveLocale } from 'hooks/useActiveLocale' -import { ReactNode } from 'react' -import { useUserLocaleManager } from 'state/user/hooks' +import { initialLocale } from 'i18n/initialLocale' -import i18n, { t } from 'i18next' -import { Trans as OGTrans, Translation, initReactI18next, useTranslation as useTranslationOG } from 'react-i18next' +import i18n from 'i18next' +import { initReactI18next } from 'react-i18next' -import { SupportedLocale } from 'constants/locales' +import { dynamicActivate } from 'i18n/dynamicActivate' import resourcesToBackend from 'i18next-resources-to-backend' export { t } from 'i18next' - -export const Trans = ((props) => { - // forces re-render on language change because it doesn't by default - useTranslation() - return {props.children} -}) satisfies typeof OGTrans - -export function useTranslation() { - if (process.env.NODE_ENV === 'test') { - return { i18n, t } - } - // eslint-disable-next-line react-hooks/rules-of-hooks - return useTranslationOG() -} - -export function Plural({ value, one, other }: { value: number; one: string; other: string }) { - const children = value === 1 ? one : other - if (process.env.NODE_ENV === 'test') { - return <>{children} - } - // ensures it re-renders when language changes - return {() => children} -} +export { Plural } from './i18n/Plural' +export { Trans } from './i18n/Trans' i18n .use(initReactI18next) .use( - resourcesToBackend((language: string, namespace: string) => { + resourcesToBackend((language: string) => { // not sure why but it tries to load es THEN es-ES, for any language, but we just want the second if (!language.includes('-')) { return } if (language === 'en-US') { - if (process.env.NODE_ENV === 'test') { - return import('./i18n/locales/source/en-US.json') - } + return enUsLocale } - return import(`./i18n/locales/${namespace}/${language}.json`) + return import(`./i18n/locales/translations/${language}.json`) }) ) .on('failedLoading', (language, namespace, msg) => { @@ -58,42 +33,20 @@ i18n i18n .init({ returnEmptyString: false, - defaultNS: 'translations', - keySeparator: '~~', + keySeparator: false, lng: 'en-US', fallbackLng: 'en-US', interpolation: { escapeValue: false, // react already safes from xss }, - react: { - transSupportBasicHtmlNodes: true, - }, }) .catch(() => undefined) -let changingTo = '' - -async function dynamicActivate(locale: SupportedLocale) { - if (i18n.language === locale || locale === changingTo) return - // since its async we need to "lock" while its changing - changingTo = locale - await i18n.changeLanguage(locale) - i18n.emit('') - changingTo = '' -} +// add default english ns right away +i18n.addResourceBundle('en-US', 'translations', { + 'en-US': { + translation: enUsLocale, + }, +}) dynamicActivate(initialLocale) - -export function LanguageProvider({ children }: { children: ReactNode }): JSX.Element { - const activeLocale = useActiveLocale() - const [userLocale, setUserLocale] = useUserLocaleManager() - const locale = userLocale || activeLocale - - useEffect(() => { - dynamicActivate(locale) - document.documentElement.setAttribute('lang', locale) - setUserLocale(locale) // stores the selected locale to persist across sessions - }, [setUserLocale, locale]) - - return <>{children} -} diff --git a/apps/web/src/i18n/LanguageProvider.tsx b/apps/web/src/i18n/LanguageProvider.tsx new file mode 100644 index 00000000000..0b7052331c1 --- /dev/null +++ b/apps/web/src/i18n/LanguageProvider.tsx @@ -0,0 +1,18 @@ +import { useActiveLocale } from 'hooks/useActiveLocale' +import { dynamicActivate } from 'i18n/dynamicActivate' +import { ReactNode, useEffect } from 'react' +import { useUserLocaleManager } from 'state/user/hooks' + +export function LanguageProvider({ children }: { children: ReactNode }): JSX.Element { + const activeLocale = useActiveLocale() + const [userLocale, setUserLocale] = useUserLocaleManager() + const locale = userLocale || activeLocale + + useEffect(() => { + dynamicActivate(locale) + document.documentElement.setAttribute('lang', locale) + setUserLocale(locale) // stores the selected locale to persist across sessions + }, [setUserLocale, locale]) + + return <>{children} +} diff --git a/apps/web/src/i18n/Plural.tsx b/apps/web/src/i18n/Plural.tsx new file mode 100644 index 00000000000..cff8d9bbef1 --- /dev/null +++ b/apps/web/src/i18n/Plural.tsx @@ -0,0 +1,10 @@ +import { Translation } from 'react-i18next' + +export function Plural({ value, one, other }: { value: number; one: string; other: string }) { + const children = value === 1 ? one : other + if (process.env.NODE_ENV === 'test') { + return <>{children} + } + // ensures it re-renders when language changes + return {() => children} +} diff --git a/apps/web/src/i18n/Trans.tsx b/apps/web/src/i18n/Trans.tsx new file mode 100644 index 00000000000..aefd1757219 --- /dev/null +++ b/apps/web/src/i18n/Trans.tsx @@ -0,0 +1,8 @@ +import { useTranslation } from 'i18n/useTranslation' +import { Trans as OGTrans } from 'react-i18next' + +export const Trans = ((props) => { + // forces re-render on language change because it doesn't by default + useTranslation() + return {props.children} +}) satisfies typeof OGTrans diff --git a/apps/web/src/i18n/dynamicActivate.tsx b/apps/web/src/i18n/dynamicActivate.tsx new file mode 100644 index 00000000000..c8f069fe6c5 --- /dev/null +++ b/apps/web/src/i18n/dynamicActivate.tsx @@ -0,0 +1,15 @@ +import { SupportedLocale } from 'constants/locales' +import i18n from 'i18next' + +let changingTo = '' + +export async function dynamicActivate(locale: SupportedLocale) { + if (i18n.language === locale || locale === changingTo) { + return + } + // since its async we need to "lock" while its changing + changingTo = locale + await i18n.changeLanguage(locale) + i18n.emit('') + changingTo = '' +} diff --git a/apps/web/src/i18n/initialLocale.ts b/apps/web/src/i18n/initialLocale.ts new file mode 100644 index 00000000000..2ef797ae716 --- /dev/null +++ b/apps/web/src/i18n/initialLocale.ts @@ -0,0 +1,6 @@ +import { DEFAULT_LOCALE } from 'constants/locales' +import { navigatorLocale, parseLocale, storeLocale } from '../hooks/useActiveLocale' +import { parsedQueryString } from '../hooks/useParsedQueryString' + +export const initialLocale = + parseLocale(parsedQueryString().lng) ?? storeLocale() ?? navigatorLocale() ?? DEFAULT_LOCALE diff --git a/apps/web/src/i18n/locales/source/en-US.json b/apps/web/src/i18n/locales/source/en-US.json index d1d11bf0881..63a34ff1ed3 100644 --- a/apps/web/src/i18n/locales/source/en-US.json +++ b/apps/web/src/i18n/locales/source/en-US.json @@ -1,1067 +1,1037 @@ { - "\n This web application is provided as a tool for users to interact with the Uniswap Protocol on\n their own initiative, with no endorsement or recommendation of cryptocurrency trading activities. In doing so,\n Uniswap is not recommending that users or potential users engage in cryptoasset trading activity, and users or\n potential users of the web application should not regard this webpage or its contents as involving any form of\n recommendation, invitation or inducement to deal in cryptoassets.\n": "\n This web application is provided as a tool for users to interact with the Uniswap Protocol on\n their own initiative, with no endorsement or recommendation of cryptocurrency trading activities. In doing so,\n Uniswap is not recommending that users or potential users engage in cryptoasset trading activity, and users or\n potential users of the web application should not regard this webpage or its contents as involving any form of\n recommendation, invitation or inducement to deal in cryptoassets.\n", - " Collected": " Collected", - "-": "-", - "(edit)": "(edit)", - "(View on Explorer)": "(View on Explorer)", - "{{amount}} UNI": "{{amount}} UNI", - "{{amt}} slippage": "{{amt}} slippage", - "{{amt}} Votes": "{{amt}} Votes", - "{{amt}}%": "{{amt}}%", - "{{baseSymbol}} and {{quoteSymbol}}": "{{baseSymbol}} and {{quoteSymbol}}", - "{{chainName}}{{versionDescription}} data is unavailable right now, but we expect the issue to be resolved shortly.": "{{chainName}}{{versionDescription}} data is unavailable right now, but we expect the issue to be resolved shortly.", - "{{count}} NFTs are listed significantly _one": "{{count}} NFTs are listed significantly ", - "{{count}} NFTs are listed significantly _other": "{{count}} NFTs are listed significantly ", - "{{count}} open limits_one": "{{count}} open limits", - "{{count}} open limits_other": "{{count}} open limits", - "{{currencySymbol}} fees don't allow for accurate exact outputs. Use the `You pay` field instead.": "{{currencySymbol}} fees don't allow for accurate exact outputs. Use the `You pay` field instead.", - "{{daysPassed}}d ago": "{{daysPassed}}d ago", - "{{depositedAmtA}} Deposited": "{{depositedAmtA}} Deposited", - "{{depositedAmtB}} Deposited": "{{depositedAmtB}} Deposited", - "{{fee}} fee tier": "{{fee}} fee tier", - "{{hoursPassed}}h ago": "{{hoursPassed}}h ago", - "{{label}} might be down right now, or you may have lost your network connection.": "{{label}} might be down right now, or you may have lost your network connection.", - "{{label}} token bridge": "{{label}} token bridge", - "{{minutesPassed}}m ago": "{{minutesPassed}}m ago", - "{{monthsPassed}}mo ago": "{{monthsPassed}}mo ago", - "{{name}} {{sym}} Price:": "{{name}} {{sym}} Price:", - "{{name}} fee": "{{name}} fee", - "{{name}} isn't traded on leading U.S. centralized exchanges or frequently swapped on Uniswap.": "{{name}} isn't traded on leading U.S. centralized exchanges or frequently swapped on Uniswap.", - "{{name}} isn't traded on leading U.S. centralized exchanges.": "{{name}} isn't traded on leading U.S. centralized exchanges.", - "{{name}}'s NFT collection on Uniswap": "{{name}}'s NFT collection on Uniswap", - "{{pct}}%": "{{pct}}%", - "{{pct}}% pool": "{{pct}}% pool", - "{{pct}}% select": "{{pct}}% select", - "{{pendingActivityCount}} Pending": "{{pendingActivityCount}} Pending", - "{{percentForSlider}}%": "{{percentForSlider}}%", - "{{reason}} Try increasing your slippage tolerance.\nNote: fee-on-transfer and rebase tokens are incompatible with Uniswap V3.": "{{reason}} Try increasing your slippage tolerance.\nNote: fee-on-transfer and rebase tokens are incompatible with Uniswap V3.", - "{{secondsPassed}}s ago": "{{secondsPassed}}s ago", - "{{sym}} Fees Earned:": "{{sym}} Fees Earned:", - "{{sym}} per {{base}}": "{{sym}} per {{base}}", - "{{sym}} per {{symB}}": "{{sym}} per {{symB}}", - "{{symA}} per {{symB}}": "{{symA}} per {{symB}}", - "{{symA}}/{{symB}} LP NFT": "{{symA}}/{{symB}} LP NFT", - "{{symA}}/{{symB}} LP Tokens": "{{symA}}/{{symB}} LP Tokens", - "{{symB}} per {{symA}}": "{{symB}} per {{symA}}", - "{{symbol}} Fees Earned:": "{{symbol}} Fees Earned:", - "{{symbol}} per {{base}}": "{{symbol}} per {{base}}", - "{{time}}m": "{{time}}m", - "{{token}} liquidity: {{name}}": "{{token}} liquidity: {{name}}", - "{{tokenB}} per {{tokenA}}": "{{tokenB}} per {{tokenA}}", - "{{unclaimedUni}} UNI": "{{unclaimedUni}} UNI", - "{{value}}": "{{value}}", - "{{versionName}} will be back soon": "{{versionName}} will be back soon", - "← Back to Pool": "← Back to Pool", - "+ New position": "+ New position", - "<0> All Proposals": "<0> All Proposals", - "<0> per <2>": "<0> per <2>", - "<0> per <3>": "<0> per <3>", - "<0> Votes": "<0> Votes", - "<0>Account analytics and accrued fees<1> ↗ ": "<0>Account analytics and accrued fees<1> ↗ ", - "<0>Tip: Removing pool tokens converts your position back into underlying tokens at the current rate, proportional to your share of the pool. Accrued fees are included in the amounts you receive.": "<0>Tip: Removing pool tokens converts your position back into underlying tokens at the current rate, proportional to your share of the pool. Accrued fees are included in the amounts you receive.", - "<0>Tip: Select an action and describe your proposal for the community. The proposal cannot be modified after submission, so please verify all information before submitting. The voting period will begin immediately and last for 7 days. To propose a custom action, <3>read the docs.": "<0>Tip: Select an action and describe your proposal for the community. The proposal cannot be modified after submission, so please verify all information before submitting. The voting period will begin immediately and last for 7 days. To propose a custom action, <3>read the docs.", - "<0>Tip: Use this tool to find v2 pools that don't automatically appear in the interface.": "<0>Tip: Use this tool to find v2 pools that don't automatically appear in the interface.", - "<0>UniswapX aggregates liquidity sources for better prices and gas free swaps.": "<0>UniswapX aggregates liquidity sources for better prices and gas free swaps.", - "<0>Unlock voting to prepare for the next proposal.": "<0>Unlock voting to prepare for the next proposal.", - "1 day": "1 day", - "1 day APR": "1 day APR", - "1 day APR refers to the amount of trading fees relative to total value locked (TVL) within a pool. 1 day APR = 24H Fees / TVL": "1 day APR refers to the amount of trading fees relative to total value locked (TVL) within a pool. 1 day APR = 24H Fees / TVL", - "1 day volume": "1 day volume", - "1 day volume is the amount of the asset that has been traded on Uniswap v3 during the past 24 hours.": "1 day volume is the amount of the asset that has been traded on Uniswap v3 during the past 24 hours.", - "1 hour": "1 hour", - "1 month": "1 month", - "1 open limit": "1 open limit", - "1 week": "1 week", - "1 year": "1 year", - "24H fees": "24H fees", - "24H volume": "24H volume", - "25%": "25%", - "50%": "50%", - "7 day volume": "7 day volume", - "75%": "75%", - "A minimum threshold of 0.25% of the total UNI supply is required to submit proposals": "A minimum threshold of 0.25% of the total UNI supply is required to submit proposals", - "A swap of this size may have a high price impact, given the current liquidity in the pool. There may be a large difference between the amount of your input token and what you will receive in the output token": "A swap of this size may have a high price impact, given the current liquidity in the pool. There may be a large difference between the amount of your input token and what you will receive in the output token", - "Accept": "Accept", - "Active": "Active", - "Active tick range": "Active tick range", - "Activity": "Activity", - "Add": "Add", - "Add {{baseSymbol}}/{{quoteSymbol}} V3 liquidity": "Add {{baseSymbol}}/{{quoteSymbol}} V3 liquidity", - "Add {{sym}}": "Add {{sym}}", - "Add <1> and <4> to Uniswap V2": "Add <1> and <4> to Uniswap V2", - "Add delegate +": "Add delegate +", - "Add liquidity": "Add liquidity", - "Add Liquidity": "Add Liquidity", - "Add liquidity cancelled": "Add liquidity cancelled", - "Add liquidity failed": "Add liquidity failed", - "Add liquidity.": "Add liquidity.", - "Add more liquidity": "Add more liquidity", - "Add to bag": "Add to bag", - "Add V2 liquidity": "Add V2 liquidity", - "Add V2 liquidity cancelled": "Add V2 liquidity cancelled", - "Add V2 liquidity failed": "Add V2 liquidity failed", - "Added {{sym}} ": "Added {{sym}} ", - "Added liquidity": "Added liquidity", - "Added Liquidity": "Added Liquidity", - "Added V2 liquidity": "Added V2 liquidity", - "Adding liquidity": "Adding liquidity", - "Adding this proposal to the queue will allow it to be executed, after a delay.": "Adding this proposal to the queue will allow it to be executed, after a delay.", - "Adding V2 liquidity": "Adding V2 liquidity", - "Address has no available claim": "Address has no available claim", - "Against": "Against", - "All time": "All time", - "All time LP fees ": "All time LP fees ", - "All time swappers": "All time swappers", - "All time volume": "All time volume", - "Allow {{sym}} (one time)": "Allow {{sym}} (one time)", - "Allow analytics": "Allow analytics", - "Allow LP token migration": "Allow LP token migration", - "Allowed": "Allowed", - "Already listed at": "Already listed at", - "Always conduct your own research before trading.": "Always conduct your own research before trading.", - "Amount": "Amount", - "An approval is needed to use this token. ": "An approval is needed to use this token. ", - "An error occurred when trying to execute this swap. You may need to increase your slippage tolerance. If that does not work, there may be an incompatibility with the token you are trading. Note: fee on transfer and rebase tokens are incompatible with Uniswap V3.": "An error occurred when trying to execute this swap. You may need to increase your slippage tolerance. If that does not work, there may be an incompatibility with the token you are trading. Note: fee on transfer and rebase tokens are incompatible with Uniswap V3.", - "Analytics": "Analytics", - "and": "and", - "and consent to its": "and consent to its", - "anytime,": "anytime,", - "anywhere.": "anywhere.", - "App": "App", - "Approaching 100 limit maximum": "Approaching 100 limit maximum", - "Approval cancelled": "Approval cancelled", - "Approval failed": "Approval failed", - "Approval pending": "Approval pending", - "Approval pending...": "Approval pending...", - "Approve": "Approve", - "Approve {{amount}}": "Approve {{amount}}", - "Approve {{sym}}": "Approve {{sym}}", - "Approve {{symbol}} spending": "Approve {{symbol}} spending", - "Approve and submit": "Approve and submit", - "Approve and swap": "Approve and swap", - "Approve in wallet": "Approve in wallet", - "Approve in your wallet": "Approve in your wallet", - "Approve token": "Approve token", - "Approved": "Approved", - "Approving": "Approving", - "Approving {{amount}}": "Approving {{amount}}", - "Approving {{sym}}": "Approving {{sym}}", - "At least {{amtA}} {{symA}} and {{amtB}} {{symB}} will be refunded to your wallet due to selected price range.": "At least {{amtA}} {{symA}} and {{amtB}} {{symB}} will be refunded to your wallet due to selected price range.", - "Auto": "Auto", - "Available on iOS and Android": "Available on iOS and Android", - "available yet": "available yet", - "Back to Pool": "Back to Pool", - "Back to wallet selection": "Back to wallet selection", - "Bag": "Bag", - "Balance on other networks": "Balance on other networks", - "Balance: {{amount}}": "Balance: {{amount}}", - "below floor price.": "below floor price.", - "below the collection’s floor price. Are you sure you want to continue?": "below the collection’s floor price. Are you sure you want to continue?", - "Best for exotic pairs.": "Best for exotic pairs.", - "Best for most pairs.": "Best for most pairs.", - "Best for stable pairs.": "Best for stable pairs.", - "Best for very stable pairs.": "Best for very stable pairs.", - "Best price route costs ~{{gasPrice}} in gas. ": "Best price route costs ~{{gasPrice}} in gas. ", - "blocked activities": "blocked activities", - "Blocked address": "Blocked address", - "Blocked on OpenSea": "Blocked on OpenSea", - "Blog": "Blog", - "Borrow cancelled": "Borrow cancelled", - "Borrow failed": "Borrow failed", - "Borrowed": "Borrowed", - "Borrowing": "Borrowing", - "Bought": "Bought", - "Brand Assets": "Brand Assets", - "Browser Wallet": "Browser Wallet", - "Build the next generation of open applications and tools.": "Build the next generation of open applications and tools.", - "Burn cancelled": "Burn cancelled", - "Burn failed": "Burn failed", - "Burned": "Burned", - "Burning": "Burning", - "Buy": "Buy", - "Buy & sell on Uniswap": "Buy & sell on Uniswap", - "Buy cancelled": "Buy cancelled", - "Buy failed": "Buy failed", - "buy fee:": "buy fee:", - "Buy or transfer NFTs to this wallet to get started.": "Buy or transfer NFTs to this wallet to get started.", - "Buy or transfer tokens to this wallet to get started.": "Buy or transfer tokens to this wallet to get started.", - "Buy, sell & trade {{name}} on Uniswap": "Buy, sell & trade {{name}} on Uniswap", - "Buy, sell & trade Ethereum and other top tokens on Uniswap": "Buy, sell & trade Ethereum and other top tokens on Uniswap", - "Buy, sell, and trade on Uniswap": "Buy, sell, and trade on Uniswap", - "Buying": "Buying", - "Buying {{symbol}} above market price": "Buying {{symbol}} above market price", - "By": "By", - "By adding liquidity you'll earn 0.3% of all trades on this pair proportional to your share of the pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.": "By adding liquidity you'll earn 0.3% of all trades on this pair proportional to your share of the pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.", - "By connecting a wallet, you agree to Uniswap Labs'": "By connecting a wallet, you agree to Uniswap Labs'", - "Cancel": "Cancel", - "Cancel {{count}} limits_one": "Cancel {{count}} limits", - "Cancel {{count}} limits_other": "Cancel {{count}} limits", - "Cancel failed": "Cancel failed", - "Cancel limit": "Cancel limit", - "Cancel limits to proceed": "Cancel limits to proceed", - "Cancel order": "Cancel order", - "Canceled": "Canceled", - "Cancellation cancelled": "Cancellation cancelled", - "Cancellation submitted": "Cancellation submitted", - "Cancellation Successful": "Cancellation Successful", - "Cancelled": "Cancelled", - "Cancelling": "Cancelling", - "Candlestick": "Candlestick", - "Careers": "Careers", - "Caution": "Caution", - "Chart type": "Chart type", - "Check network status": "Check network status", - "Check out our v3 LP walkthrough and migration guides.": "Check out our v3 LP walkthrough and migration guides.", - "Claim {{amount}} reward": "Claim {{amount}} reward", - "Claim <1> for {{name}}": "Claim <1> for {{name}}", - "Claim cancelled": "Claim cancelled", - "Claim failed": "Claim failed", - "Claim fees": "Claim fees", - "Claim UNI": "Claim UNI", - "Claim UNI reward for {{name}}": "Claim UNI reward for {{name}}", - "Claim UNI token": "Claim UNI token", - "Claim your UNI tokens": "Claim your UNI tokens", - "Claimed": "Claimed", - "Claiming": "Claiming", - "Clear all": "Clear all", - "Close": "Close", - "Closed": "Closed", - "Closed Positions": "Closed Positions", - "Collect": "Collect", - "Collect {{symbol0}}/{{symbol1}} fees": "Collect {{symbol0}}/{{symbol1}} fees", - "Collect as {{nativeWrappedSymbol}}": "Collect as {{nativeWrappedSymbol}}", - "Collect fees": "Collect fees", - "Collect fees cancelled": "Collect fees cancelled", - "Collect fees failed": "Collect fees failed", - "Collected fees": "Collected fees", - "Collecting": "Collecting", - "Collecting fees": "Collecting fees", - "Collecting fees will withdraw currently available fees for you.": "Collecting fees will withdraw currently available fees for you.", - "collection": "collection", - "collections": "collections", - "Coming soon: search and explore tokens on Avalanche Chain": "Coming soon: search and explore tokens on Avalanche Chain", - "Company": "Company", - "Complete!": "Complete!", - "Confirm": "Confirm", - "Confirm cancellation": "Confirm cancellation", - "Confirm in wallet": "Confirm in wallet", - "Confirm limit": "Confirm limit", - "Confirm send": "Confirm send", - "Confirm supply": "Confirm supply", - "Confirm swap": "Confirm swap", - "Confirm swap in wallet": "Confirm swap in wallet", - "Confirm this transaction in your wallet": "Confirm this transaction in your wallet", - "Confirm transaction in wallet": "Confirm transaction in wallet", - "Confirmation timed out. Please retry.": "Confirmation timed out. Please retry.", - "Connect": "Connect", - "Connect a wallet": "Connect a wallet", - "Connect to {{label}}": "Connect to {{label}}", - "Connect to a wallet to find pools": "Connect to a wallet to find pools", - "Connect to a wallet to view your liquidity.": "Connect to a wallet to view your liquidity.", - "Connect to a wallet to view your V2 liquidity.": "Connect to a wallet to view your V2 liquidity.", - "Connect wallet": "Connect wallet", - "Connect with us": "Connect with us", - "Connecting to {{label}}": "Connecting to {{label}}", - "Connecting wallet...": "Connecting wallet...", - "Contact us": "Contact us", - "Content not": "Content not", - "Continue": "Continue", - "Continue on v3": "Continue on v3", - "Contract Interaction": "Contract Interaction", - "Copied": "Copied", - "Copied!": "Copied!", - "Copy link": "Copy link", - "Create {{baseSymbol}}/{{quoteSymbol}} V3 pool": "Create {{baseSymbol}}/{{quoteSymbol}} V3 pool", - "Create a new governance proposal on Uniswap": "Create a new governance proposal on Uniswap", - "Create a pair": "Create a pair", - "Create pool & supply": "Create pool & supply", - "Create pool and add {{baseSymbol}}/{{quoteSymbol}} V3 liquidity": "Create pool and add {{baseSymbol}}/{{quoteSymbol}} V3 liquidity", - "Create pool cancelled": "Create pool cancelled", - "Create pool failed": "Create pool failed", - "Create pool.": "Create pool.", - "Create proposal": "Create proposal", - "Created pool": "Created pool", - "Creating pool": "Creating pool", - "Crypto purchases are not available in your region. ": "Crypto purchases are not available in your region. ", - "Currency": "Currency", - "Current price": "Current price", - "Current price:": "Current price:", - "Custom": "Custom", - "Data is unavailable at the moment; we're working on a fix": "Data is unavailable at the moment; we're working on a fix", - "Data may be outdated": "Data may be outdated", - "day": "day", - "days": "days", - "Defeated": "Defeated", - "Delegate cancelled": "Delegate cancelled", - "Delegate failed": "Delegate failed", - "Delegate votes": "Delegate votes", - "Delegate voting power to {{name}}": "Delegate voting power to {{name}}", - "Delegated": "Delegated", - "Delegated to:": "Delegated to:", - "Delegating": "Delegating", - "Delegating votes": "Delegating votes", - "Deploy cancelled": "Deploy cancelled", - "Deploy failed": "Deploy failed", - "Deployed": "Deployed", - "Deploying": "Deploying", - "Deposit amounts": "Deposit amounts", - "Deposit cancelled": "Deposit cancelled", - "Deposit failed": "Deposit failed", - "Deposit liquidity": "Deposit liquidity", - "Deposit tokens to the {{label}} network.": "Deposit tokens to the {{label}} network.", - "Deposited": "Deposited", - "Depositing": "Depositing", - "Description": "Description", - "Detailed": "Detailed", - "Details": "Details", - "Detected": "Detected", - "Developer docs": "Developer docs", - "Developers": "Developers", - "Disclaimer for UK residents": "Disclaimer for UK residents", - "Dismiss": "Dismiss", - "DNS Registrar": "DNS Registrar", - "Don’t see one of your v2 positions? <2>Import it.": "Don’t see one of your v2 positions? <2>Import it.", - "Don't have a Uniswap wallet?": "Don't have a Uniswap wallet?", - "Don't see your wallet?": "Don't see your wallet?", - "Download the Uniswap app": "Download the Uniswap app", - "Download Uniswap": "Download Uniswap", - "Earned UNI tokens represent voting shares in Uniswap governance.": "Earned UNI tokens represent voting shares in Uniswap governance.", - "Edit": "Edit", - "Edit listings": "Edit listings", - "Enter {{sym}} amount": "Enter {{sym}} amount", - "Enter a percent": "Enter a percent", - "Enter an address to trigger a UNI claim. If the address has any claimable UNI it will be sent to them on submission.": "Enter an address to trigger a UNI claim. If the address has any claimable UNI it will be sent to them on submission.", - "Enter an amount": "Enter an amount", - "Error": "Error", - "Error connecting": "Error connecting", - "Error ID: {{eventId}}": "Error ID: {{eventId}}", - "Error loading data": "Error loading data", - "ETH Registrar Controller": "ETH Registrar Controller", - "Ethereum Name Service": "Ethereum Name Service", - "Etherscan": "Etherscan", - "Event": "Event", - "Exact input only": "Exact input only", - "Execute": "Execute", - "Execute cancelled": "Execute cancelled", - "Execute failed": "Execute failed", - "Execute proposal {{proposalId}}": "Execute proposal {{proposalId}}", - "Execute proposal {{proposalKey}}.": "Execute proposal {{proposalKey}}.", - "Executed": "Executed", - "Executing": "Executing", - "Executing this proposal will enact the calldata on-chain.": "Executing this proposal will enact the calldata on-chain.", - "Execution submitted": "Execution submitted", - "Expired": "Expired", - "Expires {{timestamp}}": "Expires {{timestamp}}", - "Expiry": "Expiry", - "Explore": "Explore", - "Explore NFTs": "Explore NFTs", - "Explore NFTs on Uniswap": "Explore NFTs on Uniswap", - "Explore pools on Uniswap": "Explore pools on Uniswap", - "Explore tokens": "Explore tokens", - "Explore top {{tab}} on {{network}} on Uniswap": "Explore top {{tab}} on {{network}} on Uniswap", - "Explore top liquidity pools (v2) on Uniswap": "Explore top liquidity pools (v2) on Uniswap", - "Explore top tokens on {{network}} on Uniswap": "Explore top tokens on {{network}} on Uniswap", - "Explore Uniswap Analytics.": "Explore Uniswap Analytics.", - "Explorer": "Explorer", - "Explorers": "Explorers", - "Failed": "Failed", - "Failed to switch networks": "Failed to switch networks", - "FDV": "FDV", - "fee": "fee", - "Fee": "Fee", - "Fee tier": "Fee tier", - "fee:": "fee:", - "Fees": "Fees", - "Fees on the selected output token don't allow for accurate exact outputs. Use the `You pay` field instead.": "Fees on the selected output token don't allow for accurate exact outputs. Use the `You pay` field instead.", - "Fees: {{amount}}": "Fees: {{amount}}", - "Fetching best price...": "Fetching best price...", - "Fetching price...": "Fetching price...", - "Fetching route": "Fetching route", - "Fiat onramp powered by MoonPay USA LLC": "Fiat onramp powered by MoonPay USA LLC", - "Finalizing quote...": "Finalizing quote...", - "Floor": "Floor", - "Floor price": "Floor price", - "Follow @Uniswap on X for the latest updates": "Follow @Uniswap on X for the latest updates", - "for": "for", - "For": "For", + "account.authHeader.claimReward": "Claim {{ amount }} reward", + "account.drawer.gitVersion": "Version: ", + "account.drawer.modal.body": "Safely store and swap tokens with the Uniswap app. Available on iOS and Android.", + "account.drawer.modal.dont": "Don’t have a Uniswap wallet?", + "account.drawer.modal.scan": "Scan with Uniswap Wallet", + "account.drawer.spamToggle": "Hide unknown tokens & NFTs", + "account.porfolio.activity.cancelledBelow": "This order was canceled because your balance went below the input amount.", + "account.portfolio.activity.signLimit": "This order will not fill because your balance went below the input amount. Increase your balance to fix.", + "account.transactionSummary.addLiquidity": "Add {{ baseSymbol }}/{{ quoteSymbol }} V3 liquidity", + "account.transactionSummary.addLiquidityv2": "Add {{base} and {{quote}} to Uniswap V2", + "account.transactionSummary.approve": "Approve {{sym}}", + "account.transactionSummary.claimFor": "Claim {{currency}} for {{name}}", + "account.transactionSummary.claimReward": "Claim UNI reward for", + "account.transactionSummary.collectFees": "Collect {{ symbol0 }}/{{ symbol1 }} fees", + "account.transactionSummary.createAddLiquidity": "Create pool and add {{ baseSymbol }}/{{ quoteSymbol }} V3 liquidity", + "account.transactionSummary.createPool": "Create {{ baseSymbol }}/{{ quoteSymbol }} V3 pool", + "account.transactionSummary.decision.abstain": "Vote to abstain on proposal {{ proposalKey }} with reason "{{ reason: info.reason }}"", + "account.transactionSummary.decision.against": "Vote against proposal {{ proposalKey }} with reason "{{ reason: info.reason }}",", + "account.transactionSummary.decision.for": "Vote for proposal {{ proposalKey }} with reason "{{ reason: info.reason }}"", + "account.transactionSummary.delegateSummary": "Delegate voting power to {{ name }}", + "account.transactionSummary.depositLiquidity": "Deposit liquidity", + "account.transactionSummary.executeProposal": "Execute proposal {{ proposalKey }}.", + "account.transactionSummary.migrateLiquidity": "Migrate {{ baseSymbol }}/{{ quoteSymbol }} liquidity to V3", + "account.transactionSummary.queueProposal": "Queue proposal {{ proposalKey }}.", + "account.transactionSummary.removeLiquiditySummary": "Remove {{base}} and {{quote}}", + "account.transactionSummary.revoke": "Revoke {{sym}}", + "account.transactionSummary.sendSummary": "Sent {{amount}} to {{recipient}}", + "account.transactionSummary.submitProposal": "Submit new proposal", + "account.transactionSummary.swapExactIn": "Swap exactly for ", + "account.transactionSummary.swapExactOut": "Swap for exactly ", + "account.transactionSummary.unwrapTo": "Unwrap to {{symbol}}", + "account.transactionSummary.vote.abstain": "Vote to abstain on proposal {{ proposalKey }}", + "account.transactionSummary.vote.against": "Vote against proposal {{ proposalKey }}", + "account.transactionSummary.vote.for": "Vote for proposal {{ proposalKey }}", + "account.transactionSummary.withdrawLiquidity": "Withdraw deposited liquidity", + "account.transactionSummary.wrapTo": "Wrap {{amount}} to {{symbol}}", + "activity.pending": "{{pendingActivityCount}} Pending", + "addLiquidity.shareOfPool": "Share of pool", + "addressInput.recipient": "Recipient", + "analytics.allow.message": "We use anonymized data to enhance your experience with Uniswap Labs products.", + "analytics.allow": "Allow analytics", + "burn.input.enterAPercent.error": "Enter a percent", + "chain.here": "here.", + "chart.candlestick": "Candlestick", + "chart.error.pools": "Unable to display historical data for the current pool.", + "chart.error.tokens": "Unable to display historical data for the current token.", + "chart.line": "Line chart", + "chart.missingData": "Missing chart data", + "chart.price.high": "High", + "chart.price.low": "Low", + "chart.price.open": "Open", + "chart.settings.unavailable.label": "This setting is unavailable for the current chart", + "claim.thanks": "Thanks for being part of the Uniswap community {{heart}}", + "claim.uni.arrived": "UNI has arrived", + "commmon.automatic": "Auto", + "common.accept": "Accept", + "common.acknowledge": "I understand", + "common.activity": "Activity", + "common.add.label": "Add", + "common.add.liquidity.cancelled": "Add liquidity cancelled", + "common.add.liquidity.failed": "Add liquidity failed", + "common.add.v2.liquidity.cancelled": "Add V2 liquidity cancelled", + "common.add.v2.liquidity.failed": "Add V2 liquidity failed", + "common.added.liquidity": "Added liquidity", + "common.added.v2.liquidity": "Added V2 liquidity", + "common.addedLiquidity": "Added Liquidity", + "common.adding.liquidity": "Adding liquidity", + "common.adding.v2.liquidity": "Adding V2 liquidity", + "common.addLiquidity": "Add liquidity", + "common.addressOrENS": "Wallet address or ENS name", + "common.allTime": "All time", + "common.amount.label": "Amount", + "common.amountDeposited.label": "{{amount}} Deposited", + "common.amountInput.placeholder": "Input amount", + "common.and": "and", + "common.approval.cancelled": "Approval cancelled", + "common.approval.failed": "Approval failed", + "common.approve": "Approve", + "common.approved": "Approved", + "common.approvePending": "Approval pending...", + "common.approveSpend": "Approve {{symbol}} spending", + "common.approving": "Approving", + "common.availableIn": "Uniswap available in: ", + "common.availableOnIOSAndroid": "Available on iOS and Android", + "common.blocked.activities": "blocked activities", + "common.blocked.ifError": "If you believe this is an error, please send an email including your address to ", + "common.blocked.reason": "This address is blocked on the Uniswap Labs interface because it is associated with one or more", + "common.blockedAddress": "Blocked address", + "common.blog": "Blog", + "common.borrow.cancelled": "Borrow cancelled", + "common.borrow.failed": "Borrow failed", + "common.borrowed": "Borrowed", + "common.borrowing": "Borrowing", + "common.bought": "Bought", + "common.brandAssets": "Brand Assets", + "common.burn.cancelled": "Burn cancelled", + "common.burn.failed": "Burn failed", + "common.burned": "Burned", + "common.burning": "Burning", + "common.buy.cancelled": "Buy cancelled", + "common.buy.failed": "Buy failed", + "common.buy.label": "Buy", + "common.buyAndSell": "Buy and sell on Uniswap", + "common.buying": "Buying", + "common.by": "By", + "common.cancel.button": "Cancel", + "common.cancel.failed": "Cancel failed", + "common.cancellation.cancelled": "Cancellation cancelled", + "common.cancellationSubmitted": "Cancellation submitted", + "common.cancellationSuccessful": "Cancellation Successful", + "common.cancelled": "Cancelled", + "common.cancelling": "Cancelling", + "common.cancelOrder": "Cancel order", + "common.cantTradeTokens": "You can’t trade these tokens using the Uniswap App.", + "common.careers": "Careers", + "common.caution.label": "Caution", + "common.chartType": "Chart type", + "common.checkNetwork": "Check network status", + "common.claim.cancelled": "Claim cancelled", + "common.claim.failed": "Claim failed", + "common.claimed": "Claimed", + "common.claiming": "Claiming", + "common.claimUni": "Claim UNI token", + "common.claimUnis": "Claim your UNI tokens", + "common.clearAll": "Clear all", + "common.close": "Close", + "common.closed": "Closed", + "common.collect.button": "Collect", + "common.collect.fees.cancelled": "Collect fees cancelled", + "common.collect.fees.failed": "Collect fees failed", + "common.collected.fees": "Collected fees", + "common.collecting.fees": "Collecting fees", + "common.collection": "collection", + "common.collections": "collections", + "common.company": "Company", + "common.confirm": "Confirm", + "common.confirmCancellation": "Confirm cancellation", + "common.confirmSend.button": "Confirm send", + "common.confirmSwap": "Confirm swap in wallet", + "common.confirmTimedOut": "Confirmation timed out. Please retry.", + "common.confirmTransaction.button": "Confirm this transaction in your wallet", + "common.confirmWallet": "Confirm in wallet", + "common.connect.button": "Connect", + "common.connectAWallet.button": "Connect a wallet", + "common.connectingToChain": "Connecting to {{chainName}}", + "common.connectingWallet": "Connecting wallet...", + "common.connectToChain.button": "Connect to {{chainName}}", + "common.connectWallet.button": "Connect wallet", + "common.contactUs.button": "Contact us", + "common.continue.button": "Continue", + "common.contractInteraction": "Contract Interaction", + "common.copied": "Copied", + "common.copy.button": "Copy", + "common.copyLink.button": "Copy link", + "common.create.pool.cancelled": "Create pool cancelled", + "common.create.pool.failed": "Create pool failed", + "common.created.pool": "Created pool", + "common.creating.pool": "Creating pool", + "common.currency.amount": "${{amount}}", + "common.currency": "Currency", + "common.currentPrice.label": "Current price:", + "common.currentPrice": "Current price", + "common.custom": "Custom", + "common.dataOutdated": "Data may be outdated", + "common.defaultTradeOptions": "Default trade options", + "common.delegate.cancelled": "Delegate cancelled", + "common.delegate.failed": "Delegate failed", + "common.delegated": "Delegated", + "common.delegating": "Delegating", + "common.deploy.cancelled": "Deploy cancelled", + "common.deploy.failed": "Deploy failed", + "common.deployed": "Deployed", + "common.deploying": "Deploying", + "common.deposit.cancelled": "Deposit cancelled", + "common.deposit.failed": "Deposit failed", + "common.deposit.toNetwork": "Deposit tokens to the {{label}} network.", + "common.deposited": "Deposited", + "common.depositing": "Depositing", + "common.detailed.label": "Detailed", + "common.detected": "Detected", + "common.developers": "Developers", + "common.dismiss": "Dismiss", + "common.dnsRegistrar": "DNS Registrar", + "common.downloadUniswap": "Download Uniswap", + "common.downloadUniswapApp": "Download the Uniswap app", + "common.edit.button": "Edit", + "common.error.label": "Error", + "common.error.request": "Sorry, an error occured while processing your request. If you request support, be sure to copy the details of this error.", + "common.error.somethingWrong": "Something went wrong!", + "common.error.wrong.tryAgain": "Something went wrong. Please try again.", + "common.errorConnecting.error": "Error connecting", + "common.errorLoadingData.error": "Error loading data", + "common.ethereumNameService": "Ethereum Name Service", + "common.etherscan.link": "View on Etherscan", + "common.etherscan": "Etherscan", + "common.ethRegistrarController": "ETH Registrar Controller", + "common.execute.cancelled": "Execute cancelled", + "common.execute.failed": "Execute failed", + "common.executed": "Executed", + "common.executing": "Executing", + "common.expired": "Expired", + "common.expiry": "Expiry", + "common.explore": "Explore", + "common.explorer": "Explorer", + "common.exploreTokens": "Explore tokens", + "common.extension": "Uniswap Extension", + "common.failed.error": "Failed", + "common.failedSwitchNetwork": "Failed to switch networks", + "common.fee.caps": "Fee", + "common.fee": "fee", + "common.fees": "Fees", + "common.feesEarned.label": "{{symbol}} Fees Earned:", + "common.feesEarnedPerBase": "{{symbolA}} per {{symbolB}}", + "common.fetchingRoute": "Fetching route", + "common.floor": "Floor", + "common.floorPrice": "Floor price", + "common.for.address": "for {{ address }}", + "common.for": "For", + "common.from": "from", + "common.fullRange": "Full range", + "common.getHelp.button": "Get help", + "common.getSupport.button": "Get support", + "common.getTheApp": "Get the app", + "common.governance": "Governance", + "common.happyHolidays": "Happy Holidays from the Uniswap team!", + "common.helpCenter": "Help Center", + "common.hidden": "Hidden", + "common.hide.button": "Hide", + "common.highPrice": "High price", + "common.includes": "Includes", + "common.info.label": "Info", + "common.input.noRecipient.error": "Select recipient", + "common.insufficient.funds": "Insufficient funds", + "common.insufficientBalance.error": "Insufficient balance", + "common.insufficientFundsForNetworkFee.error": "Insufficient funds to cover network fee", + "common.insufficientLiquidity": "Insufficient liquidity", + "common.insufficientTokenBalance.error": "Insufficient {{tokenSymbol}} balance", + "common.invalidPair": "Invalid pair", + "common.invalidRecipient.error": "Invalid recipient", + "common.items": "items", + "common.language": "Language", + "common.lastPrice": "Last price", + "common.learnMore.link": "Learn more", + "common.learnMoreSwap": "Learn more about swaps", + "common.legalAndPrivacy": "Legal & Privacy", + "common.limit.cancel.amount": "Cancel {{count}} limits", + "common.limit.cancel": "Cancel limit", + "common.limit.cancelled": "Limit cancelled", + "common.limit.executed": "Limit executed", + "common.limit.expired": "Limit expired", + "common.limit.failed": "Limit failed", + "common.limit.opened": "Limit opened", + "common.limit.pending": "Limit pending", + "common.limits.approachMax": "Approaching 100 limit maximum", + "common.limits.cancelProceed": "Cancel limits to proceed", + "common.limits.expires": "Expires {{ timestamp }}", + "common.limits.open": "Open limits", + "common.limits.when": "when {{ price }} {{ outSymbol }}/{{ inSymbol }}", + "common.links": "Links", + "common.liquidity": "Liquidity", + "common.listing": "listing", + "common.listings": "listings", + "common.loading": "Loading", + "common.loadingAllowance": "Loading allowance", + "common.lowPrice": "Low price", + "common.manage": "Manage", + "common.market.label": "Market", + "common.max.caps": "MAX", + "common.max": "Max", + "common.migrate.liquidity.cancelled": "Migrate liquidity cancelled", + "common.migrate.liquidity.failed": "Migrate liquidity failed", + "common.migrate": "Migrate", + "common.migrated.liquidity": "Migrated liquidity", + "common.migrating.liquidity": "Migrating liquidity", + "common.min.label": "Min", + "common.mint.cancelled": "Mint cancelled", + "common.mint.failed": "Mint failed", + "common.minted": "Minted", + "common.minting": "Minting", + "common.mobileWallet": "Mobile Wallet", + "common.more": "More", + "common.navigationButton": "Navigation button", + "common.needHelp": "Need help?", + "common.networkCost": "Network cost", + "common.neverMind": "Never mind", + "common.nfts": "NFTs", + "common.noActivity": "No activity yet", + "common.noAmount.error": "Enter an amount", + "common.noData": "No data", + "common.noDescription": "No description.", + "common.noResults": "No results found.", + "common.notAvailable": "Not available", + "common.notCreated.label": "Not created", + "common.oneDay": "1 day", + "common.oneHour": "1 hour", + "common.oneMonth": "1 month", + "common.oneWeek": "1 week", + "common.oneYear": "1 year", + "common.orderCancelled": "Order cancelled", + "common.orderExecuted": "Order executed", + "common.orderExpired": "Order expired", + "common.orderPending": "Order pending", + "common.outOfRange": "Out of range", + "common.pageNotFound": "Page not found!", + "common.pastDay": "Past day", + "common.pastFiveMinutes": "Past five minutes", + "common.pastHour": "Past hour", + "common.pastMonth": "Past month", + "common.pastWeek": "Past week", + "common.pastYear": "Past year", + "common.pay.button": "Pay", + "common.pending.cancellation": "Pending cancellation", + "common.pending": "Pending", + "common.pendingEllipsis": "Pending...", + "common.per": "per", + "common.percentage": "{{pct}}%", + "common.permit2": "Permit2", + "common.pool": "Pool", + "common.pools": "Pools", + "common.popularTokens": "Popular tokens", + "common.positionUnavailable": "Position unavailable", + "common.preferences": "Preferences", + "common.preview": "Preview", + "common.price": "Price", + "common.priceImpact": "Price impact warning", + "common.priceUpdated": "Price updated", + "common.privacyPolicy": "Privacy Policy", + "common.proceed": "Proceed", + "common.proceedInWallet.short": "Proceed in wallet", + "common.proceedInWallet": "Proceed in your wallet", + "common.protocol": "Protocol", + "common.publicResolver": "Public Resolver", + "common.purchased": "Purchased", + "common.queue.cancelled": "Queue cancelled", + "common.queue.failed": "Queue failed", + "common.queue": "Queue", + "common.queued": "Queued", + "common.queuing": "Queuing", + "common.rate": "Rate", + "common.readMore": "Read more", + "common.receive.cancelled": "Receive cancelled", + "common.receive.failed": "Receive failed", + "common.receive": "Receive", + "common.received": "Received", + "common.receiving": "Receiving", + "common.recent": "Recent", + "common.rejected": "Rejected", + "common.reload.label": "Reload the app", + "common.remove.label": "Remove", + "common.remove.liquidity.cancelled": "Remove liquidity cancelled", + "common.remove.liquidity.failed": "Remove liquidity failed", + "common.removeAmount": "Remove amount", + "common.removed.liquidity": "Removed liquidity", + "common.removedLiquidity": "Removed Liquidity", + "common.removeItem": "Remove item", + "common.removing.liquidity": "Removing liquidity", + "common.repaid": "Repaid", + "common.repay.cancelled": "Repay cancelled", + "common.repay.failed": "Repay failed", + "common.repaying": "Repaying", + "common.resetLimit": "Reset {{symbol}} limit", + "common.resetLimitWallet": "Reset {{symbol}} limit in wallet", + "common.resettingLimit": "Resetting {{symbol}} limit...", + "common.resolveIssue": "Resolve issue", + "common.resolveIssues": "Resolve {{issues}} issues", + "common.restricted.region": "Restricted region", + "common.retry": "Retry", + "common.return.label": "Return", + "common.returnToTop": "Return to top", + "common.reverseRegistrar": "Reverse Registrar", + "common.revoke.approval.failed": "Revoke approval failed", + "common.revoked.approval": "Revoked approval", + "common.revokedApproval": "Revoked Approval", + "common.revoking.approval": "Revoking approval", + "common.samePrice": "Same price", + "common.scanQRDownload": "Scan the QR code with your phone to download the Uniswap app", + "common.search.label": "Search", + "common.searchResults": "Search results", + "common.searchTokens": "Search tokens", + "common.searchTokensNFT": "Search tokens and NFT collections", + "common.selectAction.label": "Select an action", + "common.selectToken.label": "Select a token", + "common.selectToken": "Select token", + "common.sell.label": "Sell", + "common.send.button": "Send", + "common.send.cancelled": "Send cancelled", + "common.send.failed": "Send failed", + "common.sending": "Sending", + "common.sent": "Sent", + "common.settings": "Settings", + "common.share.shareToTwitter": "Share to Twitter", + "common.share.twitter": "Share on Twitter", + "common.share": "Share", + "common.show.button": "Show", + "common.showLess.button": "Show less", + "common.showMore.button": "Show more", + "common.sign.action": "Sign", + "common.signatureExpired": "Your signature has expired.", + "common.signMessage": "Sign message", + "common.signMessageWallet": "Sign message in wallet", + "common.simple.label": "Simple", + "common.sold": "Sold", + "common.somethingWentWrong.error": "Something went wrong", + "common.stats": "Stats", + "common.stayConnected": "Stay connected", + "common.submit.proposal.cancelled": "Submit proposal cancelled", + "common.submit.proposal.failed": "Submit proposal failed", + "common.submitted.proposal": "Submitted proposal", + "common.submitting.proposal": "Submitting proposal", + "common.swap.cancelled": "Swap cancelled", + "common.swap.expired": "Swap expired", + "common.swap.failed": "Swap failed", + "common.swap": "Swap", + "common.swapped": "Swapped", + "common.swapPending": "Swap pending...", + "common.swapping": "Swapping", + "common.switchNetworks": "Switch networks", + "common.termsOfService": "Terms of Service", + "common.termsPrivacy": "Terms & Privacy", + "common.thisMonth": "This Month", + "common.thisWeek": "This Week", + "common.thisYear": "This Year", + "common.time.day": "day", + "common.time.days": "days", + "common.time.daysAbbr": "{{days}}d", + "common.time.hour": "hour", + "common.time.hours": "hours", + "common.time.hoursAbbr": "{{hours}}h", + "common.time.minute.amt": "{{time}}m", + "common.time.minute": "minute", + "common.time.minutes": "minutes", + "common.time.minutesAbbr": "{{minutes}}m", + "common.time.month": "month", + "common.time.months": "months", + "common.time.monthsAbbr": "{{months}}mo", + "common.time.second": "second", + "common.time.seconds": "seconds", + "common.time.secondsAbbr": "{{seconds}}s", + "common.time.year": "year", + "common.time.years": "years", + "common.time.yearsAbbr": "{{years}}y", + "common.time": "Time", + "common.timestamp.daysAgo": "{{daysPassed}}d ago", + "common.timestamp.hoursAgo": "{{hoursPassed}}h ago", + "common.timestamp.minutesAgo": "{{minutesPassed}}m ago", + "common.timestamp.monthsAgo": "{{monthsPassed}}mo ago", + "common.timestamp.secondsAgo": "{{secondsPassed}}s ago", + "common.tip.label": "Tip:", + "common.to.caps": "To", + "common.to": "to", + "common.today": "Today", + "common.token": "Token", + "common.tokenA": "Token A", + "common.tokenAmount": "Token amount", + "common.tokenB": "Token B", + "common.tokenName": "Token name", + "common.tokens": "Tokens", + "common.totalValueLocked": "TVL", + "common.trademarkPolicy": "Trademark Policy", + "common.transactionDetails": "Transaction details", + "common.transactionId": "Transaction ID", + "common.transactionPending": "Transaction pending", + "common.transactions": "Transactions", + "common.transactionSettings": "Transaction Settings", + "common.transactionSubmitted": "Transaction submitted", + "common.transfer": "transfer", + "common.transfers": "transfers", + "common.tryAgain.error": "Try again", + "common.twitter": "Twitter", + "common.type.label": "Type", + "common.unavailable": "Unavailable", + "common.uniGovernance": "UNI Governance", + "common.uniInterface": "Uniswap Interface", + "common.uniswapProtocol": "Uniswap Protocol", + "common.uniswapTVL": "Uniswap TVL", + "common.uniswapWallet": "Uniswap wallet", + "common.uniswapX": "UniswapX", + "common.unknown": "Unknown", + "common.UNKNOWN": "UNKNOWN", + "common.unknownApproval": "Unknown Approval", + "common.unknownError.error": "Unknown Error", + "common.unknownLend": "Unknown Lend", + "common.unknownMint": "Unknown Mint", + "common.unknownSend": "Unknown Send", + "common.unknownSwap": "Unknown Swap", + "common.unsupportedAsset_one": "Unsupported asset", + "common.unsupportedAsset_other": "Unsupported assets", + "common.untitled": "Untitled", + "common.unwrap.button": "Unwrap", + "common.unwrap.failed": "Unwrap failed", + "common.unwrapped": "Unwrapped", + "common.unwrapping": "Unwrapping", + "common.v2": "v2", + "common.v3": "v3", + "common.viewOnBlockExplorer": "View on Block Explorer", + "common.viewOnExplorer": "View on Explorer", + "common.viewTransactionExplorer.link": "View transaction on Explorer", + "common.volume.lowercase": "volume", + "common.volume": "Volume", + "common.vote.cancelled": "Vote cancelled", + "common.vote.failed": "Vote failed", + "common.voted": "Voted", + "common.voting": "Voting", + "common.wallet.approve": "Approve in wallet", + "common.wallet.label": "Wallet", + "common.wallet.unsupported": "Unsupported by your wallet", + "common.walletForSwapping": "The wallet built for swapping. Available on iOS and Android.", + "common.warning.tokenNotTraded": "{{name}} isn’t traded on leading U.S. centralized exchanges.", + "common.warning.tokenNotTradedOrSwapped": "{{name}} isn’t traded on leading U.S. centralized exchanges or frequently swapped on Uniswap.", + "common.warning.tokensNotTraded": "These tokens aren’t traded on leading U.S. centralized exchanges.", + "common.warning.tokensNotTradedOrSwapped": "These tokens aren’t traded on leading U.S. centralized exchanges or frequently swapped on Uniswap.", + "common.warning": "Warning", + "common.webApp": "Web app", + "common.website": "Website", + "common.whyApprove": "Why do I have to approve a token?", + "common.whySign": "Why are signatures required?", + "common.whyWrap": "Why do I have to wrap my {{symbol}}?", + "common.withdraw.failed": "Withdraw failed", + "common.withdrawal.cancelled": "Withdrawal cancelled", + "common.withdrawing": "Withdrawing", + "common.withdrew": "Withdrew", + "common.withinRange": "In range", + "common.wrap.button": "Wrap", + "common.wrap.cancelled": "Wrap cancelled", + "common.wrap.failed": "Wrap failed", + "common.wrap": "Wrap {{symbol}}", + "common.wrapIn": "Wrap {{symbol}} in wallet", + "common.wrapped": "Wrapped", + "common.wrapping": "Wrapping", + "common.wrappingToken": "Wrapping {{symbol}}...", + "common.wrongNetwork": "Wrong network", + "common.xPerY": " per ", + "common.your.account.had.insufficient.funds": "Your account had insufficient funds to complete this swap.", + "common.your.account.has.insufficient.funds": "Your account has insufficient funds to complete this swap.", + "common.your.limit.could.not.be.fulfilled": "Your limit could not be fulfilled at this time. Please try again.", + "common.your.swap.could.not.be.fulfilled": "Your swap could not be fulfilled at this time. Please try again.", + "common.youRecieve": "You receive", + "common.youreSending": "You’re sending", + "common.yourTokens": "Your tokens", + "common.youWillReceive": "You will receive", + "error.access.expiry": "This provides the Uniswap protocol access to your token for trading. For security, it expires after 30 days.", + "error.dataUnavailable": "Data is unavailable at the moment; we’re working on a fix", + "error.id": "Error ID: {{eventId}}", + "error.noData": "No data found", + "error.request.provideId": "Sorry, an error occured while processing your request. If you request support, be sure to provide your error ID.", + "error.tokenApproval": "Token approval failed", + "explore.unableToDisplayHistorical": "Unable to display historical volume data for the current chain.", + "explore.unableToDisplayHistoricalTVL": "Unable to display historical TVL data for the current chain.", + "explore.uniVolume": "Uniswap volume", + "fee.bestForExotic": "Best for exotic pairs.", + "fee.bestForMost": "Best for most pairs.", + "fee.bestForStable": "Best for stable pairs.", + "fee.bestForVeryStable": "Best for very stable pairs.", + "fee.percentEarned": "The % you will earn in fees.", + "fee.selectPercent": "{{pct}}% select", + "fee.tier": "Fee tier", + "fee.tierExact": "{{fee}} fee tier", + "fiatOnRamp.notAvailable.error": "Crypto purchases are not available in your region. ", "for {{address}}": "for {{address}}", - "For each pool shown below, click migrate to remove your liquidity from Uniswap V2 and deposit it into Uniswap V3.": "For each pool shown below, click migrate to remove your liquidity from Uniswap V2 and deposit it into Uniswap V3.", - "from": "from", - "Full range": "Full range", - "Fully diluted valuation (FDV) calculates the total market value assuming all tokens are in circulation.": "Fully diluted valuation (FDV) calculates the total market value assuming all tokens are in circulation.", - "Get help": "Get help", - "Get support": "Get support", - "Get the app": "Get the app", - "Go direct to DeFi": "Go direct to DeFi", - "Governance": "Governance", - "Happy Holidays from the Uniswap team!": "Happy Holidays from the Uniswap team!", - "Help Center": "Help Center", - "here.": "here.", - "Hidden": "Hidden", - "Hide": "Hide", - "Hide closed positions": "Hide closed positions", - "Hide small balances": "Hide small balances", - "Hide unknown tokens & NFTs": "Hide unknown tokens & NFTs", - "High": "High", - "High price": "High price", - "hour": "hour", - "hours": "hours", - "I understand": "I understand", - "If the price moves so that you will pay more than {{amount}}, your transaction will be reverted. This is the maximum amount you are guaranteed to pay.": "If the price moves so that you will pay more than {{amount}}, your transaction will be reverted. This is the maximum amount you are guaranteed to pay.", - "If the price moves so that you will receive less than {{amount}}, your transaction will be reverted. This is the minimum amount you are guaranteed to receive.": "If the price moves so that you will receive less than {{amount}}, your transaction will be reverted. This is the minimum amount you are guaranteed to receive.", - "If you believe this is an error, please send an email including your address to ": "If you believe this is an error, please send an email including your address to ", - "Import pool": "Import pool", - "Import V2 pool": "Import V2 pool", - "In range": "In range", - "Increase liquidity": "Increase liquidity", - "Info": "Info", - "Initial prices and pool share": "Initial prices and pool share", - "Input amount": "Input amount", - "Input is estimated. You will sell at most {{amount}} or the transaction will revert.": "Input is estimated. You will sell at most {{amount}} or the transaction will revert.", - "Insights and news from the team": "Insights and news from the team", - "Insufficient {{sym}} balance": "Insufficient {{sym}} balance", - "Insufficient {{symbol}} balance": "Insufficient {{symbol}} balance", - "Insufficient balance": "Insufficient balance", - "Insufficient funds": "Insufficient funds", - "Insufficient funds to cover network fee": "Insufficient funds to cover network fee", - "Insufficient liquidity": "Insufficient liquidity", - "Insufficient liquidity for this trade.": "Insufficient liquidity for this trade.", - "Insufficient pool liquidity to complete transaction": "Insufficient pool liquidity to complete transaction", - "Invalid pair": "Invalid pair", - "Invalid pair.": "Invalid pair.", - "Invalid price input": "Invalid price input", - "Invalid range selected. The min price must be lower than the max price.": "Invalid range selected. The min price must be lower than the max price.", - "Invalid recipient": "Invalid recipient", - "Is this a wallet address?": "Is this a wallet address?", - "is worth": "is worth", - "items": "items", - "Language": "Language", - "Last": "Last", - "Last price": "Last price", - "Learn": "Learn", - "Learn about providing liquidity": "Learn about providing liquidity", - "Learn more": "Learn more", - "Learn more about limits": "Learn more about limits", - "Learn more about swapping with UniswapX": "Learn more about swapping with UniswapX", - "Learn more about swaps": "Learn more about swaps", - "Learn why": "Learn why", - "Legal & Privacy": "Legal & Privacy", - "Limit": "Limit", - "Limit cancelled": "Limit cancelled", - "Limit executed": "Limit executed", - "Limit expired": "Limit expired", - "Limit failed": "Limit failed", - "Limit filled!": "Limit filled!", - "Limit opened": "Limit opened", - "Limit pending": "Limit pending", - "Limit price": "Limit price", - "Limit submitted": "Limit submitted", - "Limits may not execute exactly when tokens reach the specified price. <2><0>Learn more": "Limits may not execute exactly when tokens reach the specified price. <2><0>Learn more", - "Line chart": "Line chart", - "Links": "Links", - "Liquidity": "Liquidity", - "Liquidity data not available.": "Liquidity data not available.", - "Liquidity provider rewards": "Liquidity provider rewards", - "Liquidity providers earn a 0.3% fee on all trades proportional to their share of the pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.": "Liquidity providers earn a 0.3% fee on all trades proportional to their share of the pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.", - "List for sale": "List for sale", - "List NFTs": "List NFTs", - "listing": "listing", - "Listing an NFT requires a one-time marketplace approval for each NFT collection.": "Listing an NFT requires a one-time marketplace approval for each NFT collection.", - "listings": "listings", - "Loading": "Loading", - "Loading allowance": "Loading allowance", - "Low": "Low", - "Low listing price": "Low listing price", - "Low price": "Low price", - "Manage": "Manage", - "Manage {{quoteSymbol}}/{{baseSymbol}} pool liquidity on Uniswap": "Manage {{quoteSymbol}}/{{baseSymbol}} pool liquidity on Uniswap", - "Manage & provide pool liquidity on Uniswap": "Manage & provide pool liquidity on Uniswap", - "Manage & provide v2 pool liquidity on Uniswap": "Manage & provide v2 pool liquidity on Uniswap", - "Manage liquidity in rewards pool": "Manage liquidity in rewards pool", - "Manage pool liquidity on Uniswap": "Manage pool liquidity on Uniswap", - "Manage this pool.": "Manage this pool.", - "Manage v2 pool liquidity on Uniswap": "Manage v2 pool liquidity on Uniswap", - "Market": "Market", - "Market cap": "Market cap", - "Market capitalization is the total market value of an asset's circulating supply.": "Market capitalization is the total market value of an asset's circulating supply.", - "Market price not available": "Market price not available", + "for": "for", + "hero.anytime": "anytime,", + "hero.anywhere": "anywhere.", + "hero.scroll": "Scroll to learn more", + "hero.subtitle": "The largest onchain marketplace. Buy and sell crypto on Ethereum and 7+ other chains.", + "landing.buildNextGen": "Build the next generation of open applications and tools.", + "landing.connectWithUs": "Connect with us", + "landing.devDocs": "Developer docs", + "landing.directToDeFi": "Go direct to DeFi", + "landing.followOnX": "Follow @Uniswap on X for the latest updates", + "landing.protocolDescription": "Uniswap products are powered by the Uniswap Protocol. The protocol is the largest onchain marketplace, with billions of dollars in weekly volume across thousands of tokens on Ethereum and 7+ additional chains.", + "landing.provideLiquidity.message": "Provide liquidity to pools on the Uniswap Protocol and earn fees on swaps.", + "landing.provideLiquidity": "Provide Liquidity", + "landing.swapSimple": "Swapping made simple. Access thousands of tokens on 8+ chains.", + "landing.teamInsights": "Insights and news from the team", + "landing.trusted": "Trusted by millions", + "limit.cancel.cannotExecute.plural": "Your swaps could execute before cancellation is processed. Your network costs cannot be refunded. Do you wish to proceed?", + "limit.cancel.cannotExecute": "Your swap could execute before cancellation is processed. Your network costs cannot be refunded. Do you wish to proceed?", + "limit.form.limitExecutionTime.warning": "Limits may not execute exactly when tokens reach the specified price. {{learnMoreLink}}", + "limit.open.count": "{{count}} open limits", + "limit.open.one": "1 open limit", + "limitPrice.buyingAboveMarketPrice.error.description": "Your limit price is {{percentage}}% higher than market. Adjust your limit price to proceed.", + "limitPrice.buyingAboveMarketPrice.error.title": "Buying {{tokenSymbol}} above market price.error", + "limitPrice.marketPriceNotAvailable.error.description": "We are unable to calculate the current market price. To avoid submitting an order below market price, please check your network connection and try again.", + "limitPrice.marketPriceNotAvailable.error.title": "Market price not available", + "limitPrice.sellingBelowMarketPrice.error.description": "Your limit price is {{percentage}}% lower than market. Adjust your limit price to proceed.", + "limitPrice.sellingBelowMarketPrice.error.title": "Selling {{tokenSymbol}} below market price", + "limits.isWorth": "is worth", + "limits.learnMore": "Learn more about limits", + "limits.onlyMainnet": "Only Ethereum mainnet tokens are available for limits. <0>Learn more", + "limits.price.label": "Limit price", + "limits.priceWarning": "Limits may not execute exactly when tokens reach the specified price. <0>Learn more", + "limits.selectSupportedTokens": "Select supported tokens", + "limits.whenOne": "When 1", + "liquidity.notEnough.label": "Not enough liquidity to show accurate USD value.", "max": "max", - "Max": "Max", - "MAX": "MAX", - "Max creator royalties": "Max creator royalties", - "Max fees": "Max fees", - "Max price": "Max price", - "Max:": "Max:", - "Max. slippage": "Max. slippage", - "Migrate": "Migrate", - "Migrate {{baseSymbol}}/{{quoteSymbol}} liquidity to V3": "Migrate {{baseSymbol}}/{{quoteSymbol}} liquidity to V3", - "Migrate liquidity cancelled": "Migrate liquidity cancelled", - "Migrate liquidity failed": "Migrate liquidity failed", - "Migrate liquidity to V3": "Migrate liquidity to V3", - "Migrate V2 liquidity": "Migrate V2 liquidity", - "Migrate v2 pool liquidity to Uniswap v3": "Migrate v2 pool liquidity to Uniswap v3", - "Migrate your liquidity tokens from Uniswap V2 to Uniswap V3.": "Migrate your liquidity tokens from Uniswap V2 to Uniswap V3.", - "Migrated liquidity": "Migrated liquidity", - "Migrating": "Migrating", - "Migrating liquidity": "Migrating liquidity", - "Min price": "Min price", - "Min:": "Min:", - "Min: ": "Min: ", - "Mint cancelled": "Mint cancelled", - "Mint failed": "Mint failed", - "Minted": "Minted", - "Minting": "Minting", - "minutes": "minutes", - "Missing chart data": "Missing chart data", - "Mobile Wallet": "Mobile Wallet", - "month": "month", - "months": "months", - "MoonPay fiat on-ramp iframe": "MoonPay fiat on-ramp iframe", - "Moonpay is not available in some regions. Click to learn more.": "Moonpay is not available in some regions. Click to learn more.", - "More": "More", - "My NFTs": "My NFTs", - "Name not found": "Name not found", - "Navigation button": "Navigation button", - "Need help?": "Need help?", - "Network cost": "Network cost", - "Network cost is paid in {{sym}} on the {{chainName}} network in order to transact.": "Network cost is paid in {{sym}} on the {{chainName}} network in order to transact.", - "Network warning": "Network warning", - "Nevermind": "Nevermind", - "New address": "New address", - "New position": "New position", - "NFT": "NFT", - "NFT collection on Uniswap": "NFT collection on Uniswap", - "NFT collection on Uniswap - {{address}}": "NFT collection on Uniswap - {{address}}", - "NFT collections": "NFT collections", - "NFTs": "NFTs", - "No activity yet": "No activity yet", - "No collection assets exist at this address": "No collection assets exist at this address", - "No data": "No data", - "No data found": "No data found", - "No description.": "No description.", - "No items to display": "No items to display", - "No liquidity found.": "No liquidity found.", - "No NFTs yet": "No NFTs yet", - "No pool found.": "No pool found.", - "No pools yet": "No pools yet", - "No proposals found.": "No proposals found.", - "No results found.": "No results found.", - "No token information available": "No token information available", - "No tokens found.": "No tokens found.", - "No tokens yet": "No tokens yet", - "No V2 liquidity found.": "No V2 liquidity found.", - "Not available": "Not available", - "Not created": "Not created", - "Not enough liquidity to show accurate USD value.": "Not enough liquidity to show accurate USD value.", - "Not listed": "Not listed", - "On Blast, USDB and WETH are rebasing tokens that automatically earn yield. Due to incompatibility with Uniswap v3, LP positions with USDB or WETH won't earn rebasing yield, but will in Uniswap v2.": "On Blast, USDB and WETH are rebasing tokens that automatically earn yield. Due to incompatibility with Uniswap v3, LP positions with USDB or WETH won't earn rebasing yield, but will in Uniswap v2.", - "On other networks": "On other networks", - "Once you are happy with the rate click supply to review.": "Once you are happy with the rate click supply to review.", - "One NFT is listed {{delta}} ": "One NFT is listed {{delta}} ", - "Only UNI votes that were self delegated or delegated to another address before block {{startBlock}} are eligible for voting.": "Only UNI votes that were self delegated or delegated to another address before block {{startBlock}} are eligible for voting.", - "Oops, take me back to Swap": "Oops, take me back to Swap", - "Open": "Open", - "Open a new position or create a pool to get started.": "Open a new position or create a pool to get started.", - "Open limits": "Open limits", - "Order cancelled": "Order cancelled", - "Order executed": "Order executed", - "Order expired": "Order expired", - "Order pending": "Order pending", - "Order routing": "Order routing", - "Other wallets": "Other wallets", - "Out of range": "Out of range", - "Output is estimated. If the price changes by more than {{allowed}}% your transaction will revert.": "Output is estimated. If the price changes by more than {{allowed}}% your transaction will revert.", - "Output is estimated. You will receive at least {{amount}} or the transaction will revert.": "Output is estimated. You will receive at least {{amount}} or the transaction will revert.", - "Owner": "Owner", - "Page not found!": "Page not found!", - "Past day": "Past day", - "Past five minutes": "Past five minutes", - "Past hour": "Past hour", - "Past month": "Past month", - "Past week": "Past week", - "Past year": "Past year", - "Pay": "Pay", - "Pay Anyway": "Pay Anyway", - "Pay at most": "Pay at most", - "Pay with": "Pay with", - "Pending": "Pending", - "Pending...": "Pending...", - "per": "per", - "Permit approval failed": "Permit approval failed", - "Permit2": "Permit2", - "Permit2 allows token approvals to be shared and managed across different applications.": "Permit2 allows token approvals to be shared and managed across different applications.", - "Place order": "Place order", - "Please be aware that the execution for limits may vary based on real-time market fluctuations and Ethereum network congestion. Limits may not execute exactly when tokens reach the specified price.": "Please be aware that the execution for limits may vary based on real-time market fluctuations and Ethereum network congestion. Limits may not execute exactly when tokens reach the specified price.", - "Please connect to Layer 1 Ethereum": "Please connect to Layer 1 Ethereum", - "Pool": "Pool", - "Pool balances": "Pool balances", - "Pool found!": "Pool found!", - "Pool out of sync": "Pool out of sync", - "Pool tokens in rewards pool:": "Pool tokens in rewards pool:", - "Pooled {{sym}}:": "Pooled {{sym}}:", - "Pooled {{symbol}}:": "Pooled {{symbol}}:", - "Pools": "Pools", - "Popular NFT collections": "Popular NFT collections", - "Popular tokens": "Popular tokens", - "Position unavailable": "Position unavailable", - "Positions": "Positions", - "Powered by MoonPay USA LLC": "Powered by MoonPay USA LLC", - "Preferences": "Preferences", - "Preview": "Preview", - "Price": "Price", - "Price difference:": "Price difference:", - "Price impact": "Price impact", - "Price Impact": "Price Impact", - "Price impact warning": "Price impact warning", - "Price range": "Price range", - "Price updated": "Price updated", - "Price:": "Price:", - "Prices and pool share": "Prices and pool share", - "Privacy Policy": "Privacy Policy", - "Privacy Policy.": "Privacy Policy.", - "Proceed": "Proceed", - "Proceed in wallet": "Proceed in wallet", - "Proceed in your wallet": "Proceed in your wallet", - "Proceeds if sold": "Proceeds if sold", - "Proposal": "Proposal", - "Proposal submitted": "Proposal submitted", - "Proposal Title": "Proposal Title", - "Proposals": "Proposals", - "Proposals submitted by community members will appear here.": "Proposals submitted by community members will appear here.", - "Proposed action": "Proposed action", - "Proposer": "Proposer", - "Protocol": "Protocol", - "Provide Liquidity": "Provide Liquidity", - "Provide liquidity to pools (v2) on Uniswap": "Provide liquidity to pools (v2) on Uniswap", - "Provide liquidity to pools on the Uniswap Protocol and earn fees on swaps.": "Provide liquidity to pools on the Uniswap Protocol and earn fees on swaps.", - "Provide liquidity to pools on Uniswap": "Provide liquidity to pools on Uniswap", - "Public Resolver": "Public Resolver", - "Purchased": "Purchased", - "Queue": "Queue", - "Queue cancelled": "Queue cancelled", - "Queue failed": "Queue failed", - "Queue proposal {{proposalId}}": "Queue proposal {{proposalId}}", - "Queue proposal {{proposalKey}}.": "Queue proposal {{proposalKey}}.", - "Queued": "Queued", - "Queueing": "Queueing", - "Queuing": "Queuing", - "Rate": "Rate", - "Rates": "Rates", - "Read less": "Read less", - "Read more": "Read more", - "Read more about providing liquidity": "Read more about providing liquidity", - "Read more about Uniswap governance": "Read more about Uniswap governance", - "Read more about unsupported assets": "Read more about unsupported assets", - "Rebasing is unavailable on v3": "Rebasing is unavailable on v3", - "Rebasing unavailable on v3": "Rebasing unavailable on v3", - "Receive": "Receive", - "Receive at least": "Receive at least", - "Receive cancelled": "Receive cancelled", - "Receive failed": "Receive failed", - "Received": "Received", - "Receiving": "Receiving", - "Recent": "Recent", - "Recent searches": "Recent searches", - "Recents": "Recents", - "Recipient": "Recipient", - "Refunds for unavailable items will be given in ETH": "Refunds for unavailable items will be given in ETH", - "Rejected": "Rejected", - "Reload the app": "Reload the app", - "Remove": "Remove", - "Remove <2> and <5>": "Remove <2> and <5>", - "Remove amount": "Remove amount", - "Remove delegate": "Remove delegate", - "Remove from bag": "Remove from bag", - "Remove item": "Remove item", - "Remove liquidity": "Remove liquidity", - "Remove liquidity cancelled": "Remove liquidity cancelled", - "Remove liquidity failed": "Remove liquidity failed", - "Removed liquidity": "Removed liquidity", - "Removed Liquidity": "Removed Liquidity", - "Removing {{amt}} {{sym}} and {{amt2}} {{sym2}}": "Removing {{amt}} {{sym}} and {{amt2}} {{sym2}}", - "Removing {{amtA}} {{symA}} and{{amtB}} {{symB}}": "Removing {{amtA}} {{symA}} and{{amtB}} {{symB}}", - "Removing liquidity": "Removing liquidity", - "Repaid": "Repaid", - "Repay cancelled": "Repay cancelled", - "Repay failed": "Repay failed", - "Repaying": "Repaying", - "Reset {{symbol}} limit": "Reset {{symbol}} limit", - "Reset {{symbol}} limit in wallet": "Reset {{symbol}} limit in wallet", - "Resetting {{symbol}} limit...": "Resetting {{symbol}} limit...", - "Resolve {{issues}} issues": "Resolve {{issues}} issues", - "Resolve issue": "Resolve issue", - "Restricted region": "Restricted region", - "Retry": "Retry", - "Return": "Return", - "Return to My NFTs": "Return to My NFTs", - "Return to NFT Explore": "Return to NFT Explore", - "Return to top": "Return to top", - "Reverse Registrar": "Reverse Registrar", - "Review limit": "Review limit", - "Review send": "Review send", - "Review swap": "Review swap", - "Revoke {{sym}}": "Revoke {{sym}}", - "Revoke approval failed": "Revoke approval failed", - "Revoked approval": "Revoked approval", - "Revoked Approval": "Revoked Approval", - "Revoking approval": "Revoking approval", - "Safely store and swap tokens with the Uniswap app. Available on iOS and Android.": "Safely store and swap tokens with the Uniswap app. Available on iOS and Android.", - "Same price": "Same price", - "Scan QR code to connect": "Scan QR code to connect", - "Scan the QR code with your phone to download the Uniswap app": "Scan the QR code with your phone to download the Uniswap app", - "Scan with Uniswap Wallet": "Scan with Uniswap Wallet", - "Scroll to learn more": "Scroll to learn more", - "Search": "Search", - "Search name or paste address": "Search name or paste address", - "Search pools": "Search pools", - "Search results": "Search results", - "Search tokens": "Search tokens", - "Search tokens and NFT collections": "Search tokens and NFT collections", - "Select a token": "Select a token", - "Select a token to find your v2 liquidity.": "Select a token to find your v2 liquidity.", - "Select an action": "Select an action", - "Select pair": "Select pair", - "Select recipient": "Select recipient", - "Select token": "Select token", - "Selected range": "Selected range", - "Self": "Self", - "Self-delegate": "Self-delegate", - "Sell": "Sell", - "sell fee:": "sell fee:", - "Sell NFTs": "Sell NFTs", - "Selling {{symbol}} below market price": "Selling {{symbol}} below market price", - "Send": "Send", - "Send cancelled": "Send cancelled", - "Send failed": "Send failed", - "Send tokens on Uniswap": "Send tokens on Uniswap", - "Sending": "Sending", - "Sent": "Sent", - "Sent<1> to {{recipient}}": "Sent<1> to {{recipient}}", - "Set price range": "Set price range", - "Set prices to continue": "Set prices to continue", - "Settings": "Settings", - "Share": "Share", - "Share of pool": "Share of pool", - "Share of Pool:": "Share of Pool:", - "Share on Twitter": "Share on Twitter", - "Share to Twitter": "Share to Twitter", - "Show": "Show", - "Show cancelled": "Show cancelled", - "Show closed positions": "Show closed positions", - "Show less": "Show less", - "Show more": "Show more", - "Show testnets": "Show testnets", - "Sign": "Sign", - "Sign and swap": "Sign and swap", - "Sign message": "Sign message", - "Sign message in wallet": "Sign message in wallet", - "Simple": "Simple", - "Slippage below {{amt}} may result in a failed transaction": "Slippage below {{amt}} may result in a failed transaction", - "Sold": "Sold", - "Some assets are not available through this interface because they may not work well with the smart contracts or we are unable to allow trading for legal reasons.": "Some assets are not available through this interface because they may not work well with the smart contracts or we are unable to allow trading for legal reasons.", - "Some tokens take a fee when they are bought or sold, which is set by the token issuer. Uniswap does not receive any of these fees.": "Some tokens take a fee when they are bought or sold, which is set by the token issuer. Uniswap does not receive any of these fees.", - "Something went wrong": "Something went wrong", - "Something went wrong!": "Something went wrong!", - "Something went wrong. Please try again.": "Something went wrong. Please try again.", - "Sorry, an error occured while processing your request. If you request support, be sure to copy the details of this error.": "Sorry, an error occured while processing your request. If you request support, be sure to copy the details of this error.", - "Sorry, an error occured while processing your request. If you request support, be sure to provide your error ID.": "Sorry, an error occured while processing your request. If you request support, be sure to provide your error ID.", - "Start listing": "Start listing", - "Starting {{sym}} Price:": "Starting {{sym}} Price:", - "Stats": "Stats", - "Stay connected": "Stay connected", - "Submit new proposal": "Submit new proposal", - "Submit proposal cancelled": "Submit proposal cancelled", - "Submit proposal failed": "Submit proposal failed", - "Submitted proposal": "Submitted proposal", - "Submitting proposal": "Submitting proposal", - "Submitting vote": "Submitting vote", - "Succeeded": "Succeeded", - "Success": "Success", - "Successfully listed": "Successfully listed", - "Supply": "Supply", - "Supplying {{amtA}} {{symA}} and {{amtB}} {{symB}}": "Supplying {{amtA}} {{symA}} and {{amtB}} {{symB}}", - "Swap": "Swap", - "Swap <2> for exactly <6>": "Swap <2> for exactly <6>", - "Swap anyway": "Swap anyway", - "Swap cancelled": "Swap cancelled", - "Swap exactly <2> for <6>": "Swap exactly <2> for <6>", - "Swap expired": "Swap expired", - "Swap failed": "Swap failed", - "Swap pending...": "Swap pending...", - "Swap submitted": "Swap submitted", - "Swap success!": "Swap success!", - "Swapped": "Swapped", - "Swapping": "Swapping", - "Swapping made simple. Access thousands of tokens on 8+ chains.": "Swapping made simple. Access thousands of tokens on 8+ chains.", - "Swaps on the Uniswap Protocol can start and end with ETH. However, during the swap ETH is wrapped into WETH.": "Swaps on the Uniswap Protocol can start and end with ETH. However, during the swap ETH is wrapped into WETH.", - "Sweep": "Sweep", - "Switch networks": "Switch networks", - "Switch to {{label}}": "Switch to {{label}}", - "Switch to v2": "Switch to v2", - "Symbol not found": "Symbol not found", - "Terms & Privacy": "Terms & Privacy", - "Terms of Service": "Terms of Service", - "Thanks for being part of the Uniswap community <1>": "Thanks for being part of the Uniswap community <1>", - "The % you will earn in fees.": "The % you will earn in fees.", - "The app fetches blockchain data from The Graph’s hosted service.": "The app fetches blockchain data from The Graph’s hosted service.", - "The app fetches on-chain data and constructs contract calls with an Infura API.": "The app fetches on-chain data and constructs contract calls with an Infura API.", - "The app fetches the optimal trade route from a Uniswap Labs server.": "The app fetches the optimal trade route from a Uniswap Labs server.", - "The app logs anonymized usage statistics in order to improve over time.": "The app logs anonymized usage statistics in order to improve over time.", - "The app securely collects your wallet address and shares it with TRM Labs Inc. for risk and compliance reasons.": "The app securely collects your wallet address and shares it with TRM Labs Inc. for risk and compliance reasons.", - "The connection attempt failed. Please click try again and follow the steps to connect in your wallet.": "The connection attempt failed. Please click try again and follow the steps to connect in your wallet.", - "The estimated difference between the USD values of input and output amounts.": "The estimated difference between the USD values of input and output amounts.", - "The impact your trade has on the market price of this pool.": "The impact your trade has on the market price of this pool.", - "The input token cannot be transferred. There may be an issue with the input token.": "The input token cannot be transferred. There may be an issue with the input token.", - "The largest onchain marketplace. Buy and sell crypto on Ethereum and 7+ other chains.": "The largest onchain marketplace. Buy and sell crypto on Ethereum and 7+ other chains.", - "The market price is outside your specified price range. Single-asset deposit only.": "The market price is outside your specified price range. Single-asset deposit only.", - "The maximum amount you are guaranteed to spend. If the price slips any further, your transaction will revert.": "The maximum amount you are guaranteed to spend. If the price slips any further, your transaction will revert.", - "The minimum amount you are guaranteed to receive. If the price slips any further, your transaction will revert.": "The minimum amount you are guaranteed to receive. If the price slips any further, your transaction will revert.", - "The most recent block number on this network. Prices update on every block.": "The most recent block number on this network. Prices update on every block.", - "The output token cannot be transferred. There may be an issue with the output token.": "The output token cannot be transferred. There may be an issue with the output token.", - "The output token cannot be transferred. There may be an issue with the output token. Note: fee on transfer and rebase tokens are incompatible with Uniswap V3.": "The output token cannot be transferred. There may be an issue with the output token. Note: fee on transfer and rebase tokens are incompatible with Uniswap V3.", - "The price of this pool is outside of your selected range. Your position is not currently earning fees.": "The price of this pool is outside of your selected range. Your position is not currently earning fees.", - "The price of this pool is within your selected range. Your position is currently earning fees.": "The price of this pool is within your selected range. Your position is currently earning fees.", - "The ratio of tokens you add will set the price of this pool.": "The ratio of tokens you add will set the price of this pool.", - "The Uniswap invariant x*y=k was not satisfied by the swap. This usually means one of the tokens you are swapping incorporates custom behavior on transfer.": "The Uniswap invariant x*y=k was not satisfied by the swap. This usually means one of the tokens you are swapping incorporates custom behavior on transfer.", - "The wallet built for swapping. Available on iOS and Android.": "The wallet built for swapping. Available on iOS and Android.", - "Theme": "Theme", - "There is no liquidity data.": "There is no liquidity data.", - "This address is blocked on the Uniswap Labs interface because it is associated with one or more": "This address is blocked on the Uniswap Labs interface because it is associated with one or more", - "This app uses the following third-party APIs:": "This app uses the following third-party APIs:", - "This collection is blocked": "This collection is blocked", - "This fee is applied on select token pairs to ensure the best experience with Uniswap. It is paid in the output token and has already been factored into the quote.": "This fee is applied on select token pairs to ensure the best experience with Uniswap. It is paid in the output token and has already been factored into the quote.", - "This fee is applied on select token pairs to ensure the best experience with Uniswap. There is no fee associated with this swap.": "This fee is applied on select token pairs to ensure the best experience with Uniswap. There is no fee associated with this swap.", - "This month": "This month", - "This order was canceled because your balance went below the input amount.": "This order was canceled because your balance went below the input amount.", - "This pool is out of sync with market prices. Adding liquidity at the suggested ratios may result in loss of funds.": "This pool is out of sync with market prices. Adding liquidity at the suggested ratios may result in loss of funds.", - "This pool must be initialized before you can add liquidity. To initialize, select a starting price for the pool. Then, enter your liquidity price range and deposit amount. Gas fees will be higher than usual due to the initialization transaction.": "This pool must be initialized before you can add liquidity. To initialize, select a starting price for the pool. Then, enter your liquidity price range and deposit amount. Gas fees will be higher than usual due to the initialization transaction.", - "This proposal may be executed after {{eta}}.": "This proposal may be executed after {{eta}}.", - "This provides the Uniswap protocol access to your token for trading. For security, it expires after 30 days.": "This provides the Uniswap protocol access to your token for trading. For security, it expires after 30 days.", - "This route optimizes your total output by considering split routes, multiple hops, and the gas cost of each step.": "This route optimizes your total output by considering split routes, multiple hops, and the gas cost of each step.", - "This setting is unavailable for the current chart": "This setting is unavailable for the current chart", - "This token doesn't exist": "This token doesn't exist", - "This token doesn't exist on {{connectedChainLabel}}": "This token doesn't exist on {{connectedChainLabel}}", - "This tool will safely migrate your {{noun}} liquidity to V3. The process is completely trustless thanks to the": "This tool will safely migrate your {{noun}} liquidity to V3. The process is completely trustless thanks to the", - "This transaction could not be sent because the deadline has passed. Please check that your transaction deadline is not too low.": "This transaction could not be sent because the deadline has passed. Please check that your transaction deadline is not too low.", - "This transaction will not succeed due to price movement. Try increasing your slippage tolerance. Note: fee on transfer and rebase tokens are incompatible with Uniswap V3.": "This transaction will not succeed due to price movement. Try increasing your slippage tolerance. Note: fee on transfer and rebase tokens are incompatible with Uniswap V3.", - "This transaction will not succeed either due to price movement or fee on transfer. Try increasing your slippage tolerance.": "This transaction will not succeed either due to price movement or fee on transfer. Try increasing your slippage tolerance.", - "This transaction will result in a {{impact}} price impact on the market price of this pool. Do you wish to continue?": "This transaction will result in a {{impact}} price impact on the market price of this pool. Do you wish to continue?", - "This week": "This week", - "This year": "This year", - "Time": "Time", - "Tip:": "Tip:", - "to": "to", - "To": "To", - "To use Uniswap on {{label}}, switch the network in your wallet’s settings.": "To use Uniswap on {{label}}, switch the network in your wallet’s settings.", - "To view a position, you must be connected to the network it belongs to.": "To view a position, you must be connected to the network it belongs to.", - "Today": "Today", - "Token A": "Token A", - "Token amount": "Token amount", - "Token approval failed": "Token approval failed", - "Token B": "Token B", - "token data for {{tokenLink}}{{chainSuffix}}": "token data for {{tokenLink}}{{chainSuffix}}", - "Token name": "Token name", - "Token not found": "Token not found", - "Token stats and charts for {{label}} are available on <4>info.uniswap.org": "Token stats and charts for {{label}} are available on <4>info.uniswap.org", - "Tokens": "Tokens", - "Top pools": "Top pools", - "Total": "Total", - "Total value locked (TVL) is the aggregate amount of the asset available across all Uniswap v3 liquidity pools.": "Total value locked (TVL) is the aggregate amount of the asset available across all Uniswap v3 liquidity pools.", - "Trade NFTs across OpenSea & other top marketplaces on Uniswap": "Trade NFTs across OpenSea & other top marketplaces on Uniswap", - "Trademark Policy": "Trademark Policy", - "Transaction completed in ": "Transaction completed in ", - "Transaction deadline": "Transaction deadline", - "Transaction details": "Transaction details", - "Transaction ID": "Transaction ID", - "Transaction pending": "Transaction pending", - "Transaction rejected": "Transaction rejected", - "Transaction Settings": "Transaction Settings", - "Transaction submitted": "Transaction submitted", - "Transaction Submitted": "Transaction Submitted", - "Transactions": "Transactions", - "transfer": "transfer", - "Transfer token": "Transfer token", - "transfers": "transfers", - "Trusted by millions": "Trusted by millions", - "Try adjusting slippage to a higher value.": "Try adjusting slippage to a higher value.", - "Try again": "Try again", - "TVL": "TVL", - "Twitter": "Twitter", - "Type": "Type", - "UK disclaimer:": "UK disclaimer:", - "Unable to display historical data for the current pool.": "Unable to display historical data for the current pool.", - "Unable to display historical data for the current token.": "Unable to display historical data for the current token.", - "Unable to display historical TVL data for the current chain.": "Unable to display historical TVL data for the current chain.", - "Unable to display historical volume data for the current chain.": "Unable to display historical volume data for the current chain.", - "Unavailable": "Unavailable", - "Unavailable for listing": "Unavailable for listing", - "Unclaimed fees": "Unclaimed fees", - "Undetermined": "Undetermined", - "UNI {{a}}/{{b}} Burned": "UNI {{a}}/{{b}} Burned", - "UNI Governance": "UNI Governance", - "UNI has arrived": "UNI has arrived", - "UNI tokens represent voting shares in Uniswap governance. You can vote on each proposal yourself or delegate your votes to a third party.": "UNI tokens represent voting shares in Uniswap governance. You can vote on each proposal yourself or delegate your votes to a third party.", - "Uniswap | Trade crypto & NFTs safely on the top DeFi exchange": "Uniswap | Trade crypto & NFTs safely on the top DeFi exchange", - "Uniswap available in: ": "Uniswap available in: ", - "Uniswap Extension": "Uniswap Extension", - "Uniswap governance": "Uniswap governance", - "Uniswap governance is only available on Layer 1. Switch your network to Ethereum Mainnet to view Proposals and Vote.": "Uniswap governance is only available on Layer 1. Switch your network to Ethereum Mainnet to view Proposals and Vote.", - "Uniswap has granted your wish!": "Uniswap has granted your wish!", - "Uniswap Labs' Terms of Service": "Uniswap Labs' Terms of Service", - "Uniswap migration contract": "Uniswap migration contract", - "Uniswap products are powered by the Uniswap Protocol. The protocol is the largest onchain marketplace, with billions of dollars in weekly volume across thousands of tokens on Ethereum and 7+ additional chains.": "Uniswap products are powered by the Uniswap Protocol. The protocol is the largest onchain marketplace, with billions of dollars in weekly volume across thousands of tokens on Ethereum and 7+ additional chains.", - "Uniswap Protocol": "Uniswap Protocol", - "Uniswap TVL": "Uniswap TVL", - "Uniswap V2 is not available on this network.": "Uniswap V2 is not available on this network.", - "Uniswap volume": "Uniswap volume", - "Uniswap wallet": "Uniswap wallet", - "UniswapX": "UniswapX", - "Unknown": "Unknown", - "UNKNOWN": "UNKNOWN", - "Unknown Approval": "Unknown Approval", - "Unknown Error": "Unknown Error", - "Unknown Lend": "Unknown Lend", - "Unknown Mint": "Unknown Mint", - "Unknown Send": "Unknown Send", - "Unknown Swap": "Unknown Swap", - "Unlock votes": "Unlock votes", - "Unlock voting": "Unlock voting", - "Unlocking votes": "Unlocking votes", - "Unsupported asset": "Unsupported asset", - "Unsupported Asset": "Unsupported Asset", - "Unsupported assets": "Unsupported assets", - "Unsupported by your wallet": "Unsupported by your wallet", - "Untitled": "Untitled", - "Unwrap": "Unwrap", - "Unwrap <2> to {{symbol}}": "Unwrap <2> to {{symbol}}", - "Unwrap failed": "Unwrap failed", - "Unwrapped": "Unwrapped", - "Unwrapping": "Unwrapping", - "Update delegation": "Update delegation", - "v2": "v2", - "V2 liquidity": "V2 liquidity", - "v2 pools": "v2 pools", - "v3": "v3", - "V3 {{sym}} Price:": "V3 {{sym}} Price:", - "v3 pools": "v3 pools", - "Version: ": "Version: ", - "View accrued fees and analytics<1>↗": "View accrued fees and analytics<1>↗", - "View NFTs": "View NFTs", - "View on Etherscan": "View on Etherscan", - "View on Block Explorer": "View on Block Explorer", - "View on Etherscan": "View on Etherscan", - "View on Explorer": "View on Explorer", - "View transaction on Explorer": "View transaction on Explorer", - "volume": "volume", - "Volume": "Volume", - "Volume is the amount of the asset that has been traded on Uniswap v3 during the selected time frame.": "Volume is the amount of the asset that has been traded on Uniswap v3 during the selected time frame.", - "Vote": "Vote", - "Vote against": "Vote against", - "Vote against proposal {{proposalId}}": "Vote against proposal {{proposalId}}", - "Vote against proposal {{proposalKey}}": "Vote against proposal {{proposalKey}}", - "Vote against proposal {{proposalKey}} with reason "{{reason}}"": "Vote against proposal {{proposalKey}} with reason "{{reason}}"", - "Vote cancelled": "Vote cancelled", - "Vote failed": "Vote failed", - "Vote for": "Vote for", - "Vote for proposal {{proposalId}}": "Vote for proposal {{proposalId}}", - "Vote for proposal {{proposalKey}}": "Vote for proposal {{proposalKey}}", - "Vote for proposal {{proposalKey}} with reason "{{reason}}"": "Vote for proposal {{proposalKey}} with reason "{{reason}}"", - "Vote on governance proposals on Uniswap": "Vote on governance proposals on Uniswap", - "Vote to abstain on proposal {{proposalId}}": "Vote to abstain on proposal {{proposalId}}", - "Vote to abstain on proposal {{proposalKey}}": "Vote to abstain on proposal {{proposalKey}}", - "Vote to abstain on proposal {{proposalKey}} with reason "{{reason}}"": "Vote to abstain on proposal {{proposalKey}} with reason "{{reason}}"", - "Voted": "Voted", - "Voting": "Voting", - "Voting ended {{date}}": "Voting ended {{date}}", - "Voting ends approximately {{date}}": "Voting ends approximately {{date}}", - "Voting starts approximately {{date}}": "Voting starts approximately {{date}}", - "Waiting for confirmation": "Waiting for confirmation", - "Wallet": "Wallet", - "Wallet address or ENS name": "Wallet address or ENS name", - "Warning": "Warning", - "We are unable to calculate the current market price. To avoid submitting an order below market price, please check your network connection and try again.": "We are unable to calculate the current market price. To avoid submitting an order below market price, please check your network connection and try again.", - "We use anonymized data to enhance your experience with Uniswap Labs products.": "We use anonymized data to enhance your experience with Uniswap Labs products.", - "Web app": "Web app", - "Website": "Website", + "migrate.allowed": "Allowed", + "migrate.allowLpMigration": "Allow LP token migration", + "migrate.connectAccount": "You must connect an account.", + "migrate.connectWallet": "Connect to a wallet to view your V2 liquidity.", + "migrate.contract": "Uniswap migration contract", + "migrate.firstLP": "You are the first liquidity provider for this Uniswap V3 pool. Your liquidity will migrate at the current {{ source }} price.", + "migrate.highGasCost": "Your transaction cost will be much higher as it includes the gas to create the pool.", + "migrate.import": "Import it.", + "migrate.invalidRange": "Invalid range selected. The min price must be lower than the max price.", + "migrate.lpNFT": "{{symA}}/{{symB}} LP NFT", + "migrate.lpTokens": "{{ symA }}/{{ symB }} LP tokens", + "migrate.migrating": "Migrating", + "migrate.missingV2Position": "Don’t see one of your v2 positions? <0>Import it.", + "migrate.noV2Liquidity": "No V2 liquidity found.", + "migrate.positionNoFees": "Your position will not earn fees or be used in trades until the market price moves into your range.", + "migrate.priceDifference": "Price difference: ", + "migrate.priceWarning": "You should only deposit liquidity into Uniswap V3 at a price you believe is correct.
If the price seems incorrect, you can either make a swap to move the price or wait for someone else to do so.", + "migrate.refund": "At least {{ amtA }} {{ symA }} and {{ amtB }} {{ symB }} will be refunded to your wallet due to selected price range.", + "migrate.setRange": "Set price range", + "migrate.symbolPrice": "{{name}} {{sym}} Price:", + "migrate.v2Description": "This tool will safely migrate your {{ source }} liquidity to V3. The process is completely trustless thanks to the <0>Uniswap migration contract ↗", + "migrate.v2Instruction": "For each pool shown below, click migrate to remove your liquidity from Uniswap V2 and deposit it into Uniswap V3.", + "migrate.v2Subtitle": "Migrate your liquidity tokens from Uniswap V2 to Uniswap V3.", + "migrate.v2Title": "Migrate V2 liquidity", + "migrate.v3Price": "V3 {{sym}} Price:", + "mint.v3.input.invalidPrice.error": "Invalid price input", + "moonpay.poweredBy": "Fiat onramp powered by MoonPay USA LLC", + "moonpay.rampIframe": "MoonPay fiat on-ramp iframe", + "moonpay.restricted.region": "Moonpay is not available in some regions. Click to learn more.", + "network.lostConnection": "You may have lost your network connection.", + "network.mightBeDown": "{{label}} might be down right now, or you may have lost your network connection.", + "network.warning": "Network warning", + "nft.addToBag": "Add to bag", + "nft.alreadyListedAt": "Already listed at", + "nft.authorsCollectionOnUni": "{{name}}’s NFT collection on Uniswap", + "nft.availableYet": "available yet", + "nft.bag": "Bag", + "nft.belowFloorEnd": "below floor price.", + "nft.blockedCollection": "This collection is blocked", + "nft.blockedOpenSea": "Blocked on OpenSea", + "nft.buyTransferNFTToStart": "Buy or transfer NFTs to this wallet to get started.", + "nft.buyTransferTokensToStart": "Buy or transfer tokens to this wallet to get started.", + "nft.collectionOnUni": "NFT collection on Uniswap", + "nft.collections": "NFT collections", + "nft.collectonOnAddress": "NFT collection on Uniswap - {{address}}", + "nft.complete": "Complete!", + "nft.confirmBelowFloor": "below the collection’s floor price. Are you sure you want to continue?", + "nft.contentNot": "Content not", + "nft.editListings": "Edit listings", + "nft.event": "Event", + "nft.explore": "Explore NFTs", + "nft.last": "Last", + "nft.learnWhy": "Learn why", + "nft.list": "List NFTs", + "nft.listedSignificantly": "{{count}} NFTs are listed significantly", + "nft.listForSale": "List for sale", + "nft.lowPrice": "Low listing price", + "nft.maxFees": "Max fees", + "nft.maxRoyalties": "Max creator royalties", + "nft.noItems": "No items to display", + "nft.noneAtAddress": "No collection assets exist at this address", + "nft.noPools": "No pools yet", + "nft.notListed": "Not listed", + "nft.noTokens": "No tokens yet", + "nft.oneListedDelta": "One NFT is listed {{delta}}", + "nft.popularCollections": "Popular NFT collections", + "nft.proceedsIfSold": "Proceeds if sold", + "nft.refundsInEth": "Refunds for unavailable items will be given in ETH", + "nft.removeFromBag": "Remove from bag", + "nft.returnToExplore": "Return to NFT Explore", + "nft.returnToMy": "Return to My NFTs", + "nft.setPrices": "Set prices to continue", + "nft.startListing": "Start listing", + "nft.successListed": "Successfully listed", + "nft.sweep": "Sweep", + "nft.unavailableToList": "Unavailable for listing", + "nft.view": "View NFTs", + "nft.whyTransaction.reason": "Listing an NFT requires a one-time marketplace approval for each NFT collection.", + "nft.whyTransaction": "Why is a transaction required?", + "nft.willAppearHere": "Your onchain transactions and crypto purchases will appear here.", + "nft.wishGranted": "Uniswap has granted your wish!", + "nft": "NFT", + "nfts.my": "My NFTs", + "nfts.noneYet": "No NFTs yet", + "nfts.sell": "Sell NFTs", + "notFound.oops": "Oops, take me back to Swap", + "notice.uk.label": "UK disclaimer:", + "notice.uk": "This web application is provided as a tool for users to interact with the Uniswap Protocol on their own initiative, with no endorsement or recommendation of cryptocurrency trading activities. In doing so, Uniswap is not recommending that users or potential users engage in cryptoasset trading activity, and users or potential users of the web application should not regard this webpage or its contents as involving any form of recommendation, invitation or inducement to deal in cryptoassets.", + "outageBanner.message.sub": "You can still swap and provide liquidity on this chain without issue.", + "outageBanner.message": "{{ chainName }} {{ versionDescription }} data is unavailable right now, but we expect the issue to be resolved shortly.", + "outageBanner.title": "{{ versionName }} will be back soon", + "permit.approval.fail.message.": "Permit2 allows token approvals to be shared and managed across different applications.", + "permit.approval.fail": "Permit approval failed", + "polling.recentBlock": "The most recent block number on this network. Prices update on every block.", + "pool.account.analyticsFees": "Account analytics and accrued fees", + "pool.accruedFees": "View accrued fees and analytics", + "pool.activePositions.appear": "Your active V3 liquidity positions will appear here.", + "pool.activeRange": "Active tick range", + "pool.addLiquidity.seoTitle": "Add liquidity to {{tokenPair}} ({{chain}}) on Uniswap", + "pool.addMoreLiquidity": "Add more liquidity", + "pool.apr.feesNotice": "1 day APR refers to the amount of trading fees relative to total value locked (TVL) within a pool. 1 day APR = 24H Fees / TVL", + "pool.apr.oneDay": "1 day APR", + "pool.areCreating": "You are creating a pool", + "pool.areFirst": "You are the first liquidity provider.", + "pool.back": "Back to Pool", + "pool.balances": "Pool balances", + "pool.claimFees": "Claim fees", + "pool.collectAs": "Collect as {{nativeWrappedSymbol}}", + "pool.collected": " Collected", + "pool.collecting": "Collecting", + "pool.collectingFees": "Collect fees", + "pool.collectingFeesWithdraw": "Collecting fees will withdraw currently available fees for you.", + "pool.confirmSupply": "Confirm supply", + "pool.connection.networkUnsupported": "Your connected network is unsupported.", + "pool.create.pair": "Create a pair", + "pool.createAndSupply": "Create pool & supply", + "pool.depositAmounts": "Deposit amounts", + "pool.earnFees": "By adding liquidity you’ll earn 0.3% of all trades on this pair proportional to your share of the pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.", + "pool.estimatePercentToRevert": "Output is estimated. If the price changes by more than {{allowed}}% your transaction will revert.", + "pool.explorers": "Explorers", + "pool.exporeAnalytics": "Explore Uniswap Analytics.", + "pool.hideClosed": "Hide closed positions", + "pool.import.v2": "Import V2 pool", + "pool.import": "Import pool", + "pool.increaseLiquidity": "Increase liquidity", + "pool.initialShare": "Initial prices and pool share", + "pool.learn": "Learn", + "pool.learnAbout": "Read more about providing liquidity", + "pool.learnLiquidity": "Learn about providing liquidity", + "pool.learnv3LP": "Check out our v3 LP walkthrough and migration guides.", + "pool.limitFluctuation.warning": "Please be aware that the execution for limits may vary based on real-time market fluctuations and Ethereum network congestion. Limits may not execute exactly when tokens reach the specified price.", + "pool.liquidity.connectToAdd": "Connect to a wallet to view your liquidity.", + "pool.liquidity.earn.fee": "Liquidity providers earn a 0.3% fee on all trades proportional to their share of the pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.", + "pool.liquidity.outOfSync.message": "This pool is out of sync with market prices. Adding liquidity at the suggested ratios may result in loss of funds.", + "pool.liquidity.outOfSync": "Pool out of sync", + "pool.liquidity.ownershipWarning.message": "You are not the owner of this LP position. You will not be able to withdraw the liquidity from this position unless you own the following address: {{ ownerAddress }}", + "pool.liquidity.rewards": "Liquidity provider rewards", + "pool.liquidity.taxWarning.message": "One or more of these tokens have taxes on transfers. Adding liquidity with V3 may result in loss of funds. Try using V2 instead.", + "pool.liquidity.taxWarning": "Token taxes", + "pool.liquidityPoolFeesNotice": "When you add liquidity, you will receive pool tokens representing your position. These tokens automatically earn fees proportional to your share of the pool, and can be redeemed at any time.", + "pool.manageRewardsLiquidity": "Manage liquidity in rewards pool", + "pool.max.label": "Max:", + "pool.maxPrice": "Max price", + "pool.min.label": "Min:", + "pool.minPrice": "Min price", + "pool.mustBeInitialized": "This pool must be initialized before you can add liquidity. To initialize, select a starting price for the pool. Then, enter your liquidity price range and deposit amount. Gas fees will be higher than usual due to the initialization transaction.", + "pool.newPosition.plus": "+ New position", + "pool.newPosition": "New position", + "pool.noLiquidity": "No liquidity found.", + "pool.onceHappyReview": "Once you are happy with the rate click supply to review.", + "pool.openToStart": "Open a new position or create a pool to get started.", + "pool.owner": "Owner", + "pool.percent": "{{pct}}% pool", + "pool.pooled": "Pooled {{sym}}:", + "pool.position.100.at": "Your position will be 100% {{symbol}} at this price.", + "pool.position.100": "Your position will be 100% at this price.", + "pool.position.networkConnect": "To view a position, you must be connected to the network it belongs to.", + "pool.position.willBe100": "Your position will be 100% composed of {{sym}} at this price", + "pool.position": "Your positions", + "pool.positions": "Positions", + "pool.priceRange": "Price range", + "pool.rangeBadge.tooltip.outsideRange": "The price of this pool is outside of your selected range. Your position is not currently earning fees.", + "pool.rangeBadge.tooltip.text": "Your position has 0 liquidity, and is not earning fees.", + "pool.rangeBadge.tooltip.withinRange": "The price of this pool is within your selected range. Your position is currently earning fees.", + "pool.rates": "Rates", + "pool.ratioTokenToPrice": "The ratio of tokens you add will set the price of this pool.", + "pool.removeLiquidity": "Remove liquidity", + "pool.rewardsPool.label": "Pool tokens in rewards pool:", + "pool.selectedRange": "Selected range", + "pool.selectPair": "Select pair", + "pool.share.label": "Your pool share:", + "pool.share": "Prices and pool share", + "pool.shareOf": "Share of Pool:", + "pool.showClosed": "Show closed positions", + "pool.startingPrice": "Starting {{sym}} Price:", + "pool.supply": "Supply", + "pool.supplyingMaths": "Supplying {{amtA}} {{symA}} and {{amtB}} {{symB}}", + "pool.top": "Top pools", + "pool.totalTokens": "Your total pool tokens:", + "pool.unclaimedFees": "Unclaimed fees", + "pool.v2.add": "Add V2 liquidity", + "pool.v2.migratev3": "Migrate liquidity to V3", + "pool.v2": "v2 pools", + "pool.v2liquidity": "V2 liquidity", + "pool.v3": "v3 pools", + "pool.volume.sevenDay": "7 day volume", + "pool.yourBalances": "Your balances", + "pool.yourv2": "Your V2 liquidity", + "poolFinder.connect": "Connect to a wallet to find pools.", + "poolFinder.create": "Create pool", + "poolFinder.found": "Pool found!", + "poolFinder.managePool": "Manage this pool", + "poolFinder.noLiquidity": "You don’t have liquidity in this pool yet.", + "poolFinder.noPoolFound": "No pool found.", + "poolFinder.selectToken": "Select a token to find your v2 liquidity.", + "poolFinder.tip": "Tip: Use this tool to find v2 pools that don’t automatically appear in the interface.", + "pools.approving.amount": "Approving {{amount}}", + "position.appearHere": "Your position will appear here.", + "position.noLiquidity": "Liquidity data not available.", + "position.noLiquidityData": "There is no liquidity data.", + "position.your": "Your position", + "privacy.anonymizedLogs": "The app logs anonymized usage statistics in order to improve over time.", + "privacy.autoRouter": "The app fetches the optimal trade route from a Uniswap Labs server.", + "privacy.infura": "The app fetches on-chain data and constructs contract calls with an Infura API.", + "privacy.theGraph": "The app fetches blockchain data from The Graph’s hosted service.", + "privacy.thirdPartyApis": "This app uses the following third-party APIs:", + "privacy.trm": "The app securely collects your wallet address and shares it with TRM Labs Inc. for risk and compliance reasons.", + "privacy.uniswaptos": "Uniswap Labs’ Terms of Service", + "proposal.action": "Proposed action", + "proposal.connectLayer1": "Please connect to Layer 1 Ethereum", + "proposal.executionSubmitted": "Execution submitted", + "proposal.layer1Warning": "Uniswap governance is only available on Layer 1. Switch your network to Ethereum Mainnet to view Proposals and Vote.", + "proposal.noneFound": "No proposals found.", + "proposal.queue.delay": "Adding this proposal to the queue will allow it to be executed, after a delay.", + "proposal.queueId": "Queue proposal {{proposalId}}", + "proposal.queueing": "Queueing", + "proposal.readTheDocs": "read the docs", + "proposal.title": "Proposal Title", + "proposal.willAppearHere": "Proposals submitted by community members will appear here.", + "proposal.willEnact": "Executing this proposal will enact the calldata on-chain.", + "removeLiquidity.collectFees": "You will also collect fees earned from this position.", + "removeLiquidity.outputEstimated": "Output is estimated. If the price changes by more than {{ allowed }}% your transaction will revert.", + "removeLiquidity.pendingText": "Removing {{ amtA }} {{ symA }} and {{ amtB }} {{ symB }}", + "removeLiquidity.pooled": "Pooled {{ symbol }}:", + "removeLiquidity.removing": "Removing {{ amt1 }} {{ symbol1}} and {{ amt2 }} {{ symbol2 }}", + "removeLiquidity.removingTokensTip": "Tip: Removing pool tokens converts your position back into underlying tokens at the current rate, proportional to your share of the pool. Accrued fees are included in the amounts you receive.", + "removeLiquidity.uniBurned": "UNI {{a}}/{{b}} Burned", + "routing.aggregateLiquidity": "When available, aggregates liquidity sources for better prices and gas free swaps.", + "routing.cheapest": "The Uniswap client selects the cheapest trade option factoring price and network costs.", + "search.avalancheComing": "Coming soon: search and explore tokens on Avalanche Chain", + "search.recent": "Recent searches", + "search.ukDisclaimer": "Disclaimer for UK residents", + "sendRecipientForm.recentAddresses.label": "Recents", + "sendReviewModal.title": "Review send", + "settings.hideSmallBalances": "Hide small balances", + "settings.maxSlippage": "Max. slippage", + "settings.showTestNets": "Show testnets", + "settings.switchNetwork.warning": "To use Uniswap on {{label}}, switch the network in your wallet’s settings.", + "speedBump.newAddress.warning.description": "You haven’t transacted with this address before. Make sure it’s the correct address before continuing.", + "speedBump.newAddress.warning.title": "New address", + "speedBump.smartContractAddress.warning.description": "You’re about to send tokens to a special type of address - a smart contract. Double-check it’s the address you intended to send to. If it’s wrong, your tokens could be lost forever.", + "speedBump.smartContractAddress.warning.title": "Is this a wallet address?", + "stats.24fees": "24H fees", + "stats.24volume": "24H volume", + "stats.allTimeFees": "All time LP fees", + "stats.allTimeSwappers": "All time swappers", + "stats.allTimeVolume": "All time volume", + "stats.fdv.description": "Fully diluted valuation (FDV) calculates the total market value assuming all tokens are in circulation.", + "stats.fdv": "FDV", + "stats.marketCap.description": "Market capitalization is the total market value of an asset’s circulating supply.", + "stats.marketCap": "Market cap", + "stats.tvl.description": "Total value locked (TVL) is the aggregate amount of the asset available across all Uniswap v3 liquidity pools.", + "stats.volume.1d.description": "1 day volume is the amount of the asset that has been traded on Uniswap v3 during the past 24 hours.", + "stats.volume.1d": "1 day volume", + "stats.volume.description": "Volume is the amount of the asset that has been traded on Uniswap v3 during the selected time frame.", + "swap.allow.oneTime": "Allow {{sym}} (one time)", + "swap.approvalNeeded": "An approval is needed to use this token. ", + "swap.approvalPending": "Approval pending", + "swap.approveAndSubmit": "Approve and submit", + "swap.approveAndSwap": "Approve and swap", + "swap.approveInWallet": "Approve in your wallet", + "swap.balance.amount": "Balance: {{amount}}", + "swap.bestRoute.cost": "Best price route costs ~{{gasPrice}} in gas. ", + "swap.confirmLimit": "Confirm limit", + "swap.confirmSwap": "Confirm swap", + "swap.enterAmount": "Enter {{sym}} amount", + "swap.error.expectedToFail": "Your swap is expected to fail.", + "swap.error.modifiedByWallet": "Your swap was modified through your wallet. If this was a mistake, please cancel immediately or risk losing your funds.", + "swap.estimatedDifference.label": "The estimated difference between the USD values of input and output amounts.", + "swap.fail.message": "Try adjusting slippage to a higher value.", + "swap.fail.uniswapX": "Swap couldn’t be completed with UniswapX. Try your swap again to route it through the classic Uniswap API.", + "swap.failed.label": "Your swap could not be executed. Please check your network connection and your slippage settings.", + "swap.fees.experience": "Fees are applied to ensure the best experience with Uniswap, and have already been factored into this quote.", + "swap.fees.noFee": "Fees are applied to ensure the best experience with Uniswap. There is no fee associated with this swap.", + "swap.fetchingBestPrice": "Fetching best price...", + "swap.fetchingPrice": "Fetching price...", + "swap.finalizingQuote": "Finalizing quote...", + "swap.form.insufficientLiquidity": "Insufficient liquidity for this trade.", + "swap.form.pay": "You pay", + "swap.form.pocketUniverseExtension.warning": "The Pocket Universe extension violates our by modifying our product in a way that is misleading and could harm users. Please disable the extension and reload the page.", + "swap.form.swapAnywayAction": "Swap anyway", + "swap.frontrun.warning": "Your transaction may be frontrun and result in an unfavorable trade.", + "swap.impactOfTrade": "The impact your trade has on the market price of this pool.", + "swap.inputEstimated.atMost": "Input is estimated. You will sell at most or the transaction will revert.", + "swap.limit": "Limit", + "swap.limitedAssets.warning": "Some assets are not available through this interface because they may not work well with the smart contracts or we are unable to allow trading for legal reasons.", + "swap.limitFilled": "Limit filled!", + "swap.limitSubmitted": "Limit submitted", + "swap.marketPrice.outsideRange.label": "The market price is outside your specified price range. Single-asset deposit only.", + "swap.maxPriceSlip.revert": "The maximum amount you are guaranteed to spend. If the price slips any further, your transaction will revert.", + "swap.minPriceSlip.revert": "The minimum amount you are guaranteed to receive. If the price slips any further, your transaction will revert.", + "swap.namedFee": "{{name}} fee", + "swap.networkCost.paidIn": "Network cost is paid in {{sym}} on the {{chainName}} network in order to transact.", + "swap.orderRouting": "Order routing", + "swap.outputEstimated.atLeast": "Output is estimated. You will receive at least or the transaction will revert.", + "swap.payAnyway": "Pay Anyway", + "swap.payAtMost": "Pay at most", + "swap.payWith": "Pay with", + "swap.placeOrder": "Place order", + "swap.priceImpact.high": "A swap of this size may have a high price impact, given the current liquidity in the pool. There may be a large difference between the amount of your input token and what you will receive in the output token", + "swap.priceImpact.upperCase": "Price Impact", + "swap.priceImpact": "Price impact", + "swap.receive.atLeast": "Receive at least", + "swap.review": "Review swap", + "swap.reviewLimit": "Review limit", + "swap.route.optimizedGasCost": "This route optimizes your total output by considering split routes, multiple hops, and the gas cost of each step.", + "swap.settings.transactionRevertPrice": "Your transaction will revert if the price changes unfavorably by more than this percentage.", + "swap.signAndSwap": "Sign and swap", + "swap.slippage.amt": "{{amt}} slippage", + "swap.slippage.exactIn.revert": "If the price moves so that you will receive less than {{amount}}, your transaction will be reverted. This is the minimum amount you are guaranteed to receive.", + "swap.slippage.exactOut.revert": "If the price moves so that you will pay more than {{amount}}, your transaction will be reverted. This is the maximum amount you are guaranteed to pay.", + "swap.slippageBelow.warning": "Slippage below {{amt}} may result in a failed transaction", + "swap.submitted": "Swap submitted", + "swap.success": "Swap success!", + "swap.taxTooltip.label": "Exact input only", + "swap.taxTooltip.noTokenSelected": "Fees on the selected output token don’t allow for accurate exact outputs. Use the `Sell` field instead.", + "swap.taxTooltip.tokenSelected": "{{tokenSymbol}} fees don’t allow for accurate exact outputs. Use the `Sell` field instead.", + "swap.tokenOwnFees": "Some tokens take a fee when they are bought or sold, which is set by the token issuer. Uniswap does not receive any of these fees.", + "swap.total": "Total", + "swap.transaction.deadline": "Transaction deadline", + "swap.transaction.revertAfter": "Your transaction will revert if it is pending for more than this period of time.", + "swap.unsupportedAssets.readMore": "Read more about unsupported assets", + "swap.warning.priceImpact": "This transaction will result in a price impact on the market price of this pool. Do you wish to continue?", + "swap.wrap.token": "Wrap {{sym}}", + "tdp.balanceSummary.otherNetworks": "On other networks", + "tdp.balanceSummary.otherNetworksBalance": "Balance on other networks", + "tdp.balanceSummary.title": "Your balance", + "tdp.invalidTokenPage.switchChainPrompt": "Switch to {{network}}", + "tdp.invalidTokenPage.title": "This token doesn’t exist", + "tdp.invalidTokenPage.titleWithChain": "This token doesn’t exist on {{network}}", + "tdp.loading.title": "token data for {{tokenLink}}{{chainSuffix}}", + "tdp.nameNotFound": "Name not found", + "tdp.noInfoAvailable": "No token information available", + "tdp.stats.unsupportedChainDescription": "Token stats and charts for {{ chain }} are available on {{ infoLink }}", + "tdp.symbolNotFound": "Symbol not found", + "themeToggle.theme": "Theme", + "title.betterPricesMoreListings": "Better prices. More listings. Buy, sell, and trade NFTs across top marketplaces like OpenSea. Explore trending collections.", + "title.buySellTradeEthereum": "Buy, sell & trade Ethereum and other top tokens on Uniswap", + "title.createGovernanceOn": "Create a new governance proposal on Uniswap", + "title.createGovernanceTo": "Create a new governance proposal to be voted on by UNI holders. UNI tokens represent voting shares in Uniswap governance.", + "title.earnFees": "Earn fees when others swap on Uniswap by adding tokens to liquidity pools.", + "title.easilyRemove": "Easily remove your liquidity from Uniswap v2 and deposit into Uniswap v3.", + "title.explore": "Explore NFTs on Uniswap", + "title.exploreNFTs": "Explore and buy NFTs across top marketplaces on Uniswap", + "title.importLiquidityv2": "Import top liquidity pools (v2) on Uniswap", + "title.manageNFT": "Manage your NFT collection. View traits, trading activity, descriptions, and other details on your NFTs.", + "title.migratev2": "Migrate v2 pool liquidity to Uniswap v3", + "title.placeLimit": "Place limit orders on Uniswap", + "title.realTime": "Real-time prices, charts, transaction data, and more.", + "title.removeLiquidityv2": "Remove pool liquidity (v2) on Uniswap", + "title.removePoolLiquidity": "Remove pool liquidity on Uniswap", + "title.removeTokensv2": "Remove your tokens from v2 liquidity pools.", + "title.removev3Liquidity": "Remove your tokens from v3 liquidity pools.", + "title.sendTokens": "Send tokens on Uniswap", + "title.swappingMadeSimple": "Swapping made simple. Buy and sell crypto on Ethereum, Base, Arbitrum, Polygon, and more. Trusted by millions.", + "title.tradeTokens": "Trade tokens and provide liquidity. Real-time prices, charts, transaction data, and more.", + "title.uniswapTradeCrypto": "Uniswap | Trade crypto and NFTs safely on the top DeFi platform", + "title.uniToken": "UNI tokens represent voting shares in Uniswap governance. You can vote on each proposal yourself or delegate your votes to a third party.", + "title.useImportTool": "Use this import tool to find v2 pools that don’t automatically appear in the interface.", + "title.voteOnGov": "Vote on governance proposals on Uniswap", + "token.bridge": "{{label}} token bridge", + "token.fee.buy.label": "buy fee:", + "token.fee.label": "fee:", + "token.fee.sell.label": "sell fee:", + "token.safety.cantTrade": "You can’t trade {{name}} using the Uniswap App.", + "token.safetyWarning": "Always conduct your own research before trading.", + "token.wrap.fail.message": "Swaps on the Uniswap Protocol can start and end with ETH. However, during the swap ETH is wrapped into WETH.", + "tokens.noneFound": "No tokens found.", + "transaction.insufficientLiquidity": "Insufficient pool liquidity to complete transaction", + "uni.addDelegate": "Add delegate +", + "uni.claim.notAvailable": "Address has no available claim", + "uni.claim": "Claim UNI", + "uni.delegateVotes": "Delegate votes", + "uni.delegatingVotes": "Delegating votes", + "uni.removeDelegate": "Remove delegate", + "uni.selfDelegate": "Self-delegate", + "uni.unlockingVotes": "Unlocking votes", + "uni.voteOrDelegate": "You can either vote on each proposal yourself or delegate your votes to a third party.", + "uni.votingShares": "Earned UNI tokens represent voting shares in Uniswap governance.", + "uni.welcome": "Welcome to team Unicorn :) ", + "uniswapX.aggregatesLiquidity": " aggregates liquidity sources for better prices and gas free swaps.", + "uniswapX.learnMore": "Learn more about swapping with UniswapX", + "uniswapx.v2QuoteFailed": "UniswapX v2 hard quote failed. Retry with classic swap.", + "unitag.addressClaim": "Enter an address to trigger a UNI claim. If the address has any claimable UNI it will be sent to them on submission.", + "v2.notAvailable": "Uniswap V2 is not available on this network.", + "v2.switchTo": "Switch to v2", + "v3.blast.yield.usdbAndWeth": "On Blast, USDB and WETH are rebasing tokens that automatically earn yield. Due to incompatibility with Uniswap v3, LP positions with USDB or WETH won’t earn rebasing yield, but will in Uniswap v2.", + "v3.continue": "Continue on v3", + "v3.rebase.unavailable": "Rebasing is unavailable on v3", + "vote.create.prompt": "Tip: Select an action and describe your proposal for the community. The proposal cannot be modified after submission, so please verify all information before submitting. The voting period will begin immediately and last for 7 days. To propose a custom action, <0>read the docs.", + "vote.landing.createProposal": "Create proposal", + "vote.landing.delegatedTo": "Delegated to:", + "vote.landing.edit": "(edit)", + "vote.landing.minThresholdRequired.error": "A minimum threshold of 0.25% of the total UNI supply is required to submit proposals.", + "vote.landing.proposals": "Proposals", + "vote.landing.readMoreAboutUniswapGovernance.link": "Read more about Uniswap governance", + "vote.landing.self": "Self", + "vote.landing.showCancelled": "Show cancelled", + "vote.landing.uniswapGovernance": "Uniswap governance", + "vote.landing.unlockVoting": "Unlock voting", + "vote.landing.voteAmount": "{{ amount }} Votes", + "vote.proposal.activeOrPendingProposal": "You already have an active or pending proposal", + "vote.proposal.approveToken": "Approve token", + "vote.proposal.notEnoughVotes": "You don’t have enough votes to submit a proposal", + "vote.proposal.submitted": "Proposal submitted", + "vote.proposal.title": "Proposal", + "vote.proposal.transferToken": "Transfer token", + "vote.proposal.voteThreshold": "You must have {{ formattedProposalThreshold }} votes to submit a proposal", + "vote.styled.active": "Active", + "vote.styled.defeated": "Defeated", + "vote.styled.succeeded": "Succeeded", + "vote.styled.undetermined": "Undetermined", + "vote.submitting": "Submitting vote", + "vote.votePage.against": "Against", + "vote.votePage.allProposals": "{{ arrow }} All Proposals", + "vote.votePage.description": "Description", + "vote.votePage.details": "Details", + "vote.votePage.execute": "Execute", + "vote.votePage.mayBeExecutedAfter": "This proposal may be executed after {{ eta }}.", + "vote.votePage.onlyUniVotesBeforeBlockEligible": "Only UNI votes that were self delegated or delegated to another address before block {{ startBlock }} are eligible for voting.", + "vote.votePage.proposer": "Proposer", + "vote.votePage.unlockVotes": "Unlock votes", + "vote.votePage.unlockVotingLink": "{{ link }} to prepare for the next proposal.", + "vote.votePage.updateDelegation": "Update delegation", + "vote.votePage.voteAgainst": "Vote against", + "vote.votePage.voteFor": "Vote for", + "vote.votePage.votingEnded": "Voting ended {{ date }}", + "vote.votePage.votingEnds": "Voting ends approximately {{ date }}", + "vote.votePage.votingStarts": "Voting starts approximately {{ date }}", + "wallet.backToSelection": "Back to wallet selection", + "wallet.connectingAgreement": "By connecting a wallet, you agree to Uniswap Labs’", + "wallet.connectionFailed.message": "The connection attempt failed. Please click try again and follow the steps to connect in your wallet.", + "wallet.networkUnsupported": "Your wallet’s current network is unsupported.", + "wallet.other": "Other wallets", + "wallet.privacyPolicyPeriod": "Privacy Policy.", + "wallet.scanToConnect": "Scan QR code to connect", + "wallet.termsAndConsent": "and consent to its", + "wallet.wrongNet": "Your wallet is connected to the wrong network.", "week": "week", - "weeks": "weeks", - "Welcome to team Unicorn :) ": "Welcome to team Unicorn :) ", - "when {{price}} {{outSymbol}}/{{inSymbol}}": "when {{price}} {{outSymbol}}/{{inSymbol}}", - "When 1": "When 1", - "When available, aggregates liquidity sources for better prices and gas free swaps.": "When available, aggregates liquidity sources for better prices and gas free swaps.", - "When you add liquidity, you will receive pool tokens representing your position. These tokens automatically earn fees proportional to your share of the pool, and can be redeemed at any time.": "When you add liquidity, you will receive pool tokens representing your position. These tokens automatically earn fees proportional to your share of the pool, and can be redeemed at any time.", - "Why are signatures required?": "Why are signatures required?", - "Why do I have to approve a token?": "Why do I have to approve a token?", - "Why do I have to wrap my {{symbol}}?": "Why do I have to wrap my {{symbol}}?", - "Why is a transaction required?": "Why is a transaction required?", - "Withdraw deposited liquidity": "Withdraw deposited liquidity", - "Withdraw failed": "Withdraw failed", - "Withdrawal cancelled": "Withdrawal cancelled", - "Withdrawing": "Withdrawing", - "Withdrew": "Withdrew", - "Wrap": "Wrap", - "Wrap {{symbol}} in wallet": "Wrap {{symbol}} in wallet", - "Wrap {{sym}}": "Wrap {{sym}}", - "Wrap {{symbol}}": "Wrap {{symbol}}", - "Wrap <2> to {{symbol}}": "Wrap <2> to {{symbol}}", - "Wrap cancelled": "Wrap cancelled", - "Wrap failed": "Wrap failed", - "Wrapped": "Wrapped", - "Wrapping": "Wrapping", - "Wrapping {{symbol}}...": "Wrapping {{symbol}}...", - "Wrong network": "Wrong network", - "You already have an active or pending proposal": "You already have an active or pending proposal", - "You are creating a pool": "You are creating a pool", - "You are not the owner of this LP position. You will not be able to withdraw the liquidity from this position unless you own the following address: {{ownerAddress}}": "You are not the owner of this LP position. You will not be able to withdraw the liquidity from this position unless you own the following address: {{ownerAddress}}", - "You are the first liquidity provider for this Uniswap V3 pool. Your liquidity will migrate at the current {{name}} price.": "You are the first liquidity provider for this Uniswap V3 pool. Your liquidity will migrate at the current {{name}} price.", - "You are the first liquidity provider.": "You are the first liquidity provider.", - "You can either vote on each proposal yourself or delegate your votes to a third party.": "You can either vote on each proposal yourself or delegate your votes to a third party.", - "You can still swap and provide liquidity on this chain without issue.": "You can still swap and provide liquidity on this chain without issue.", - "You can't trade {{name}} using the Uniswap App.": "You can't trade {{name}} using the Uniswap App.", - "You don’t have liquidity in this pool yet.": "You don’t have liquidity in this pool yet.", - "You don't have enough votes to submit a proposal": "You don't have enough votes to submit a proposal", - "You haven't transacted with this address before. Make sure it's the correct address before continuing.": "You haven't transacted with this address before. Make sure it's the correct address before continuing.", - "You may have lost your network connection.": "You may have lost your network connection.", - "You must connect an account.": "You must connect an account.", - "You must have {{formattedProposalThreshold}} votes to submit a proposal": "You must have {{formattedProposalThreshold}} votes to submit a proposal", - "You pay": "You pay", - "You receive": "You receive", - "You should only deposit liquidity into Uniswap V3 at a price you believe is correct. <1>If the price seems incorrect, you can either make a swap to move the price or wait for someone else to do so.": "You should only deposit liquidity into Uniswap V3 at a price you believe is correct. <1>If the price seems incorrect, you can either make a swap to move the price or wait for someone else to do so.", - "You will also collect fees earned from this position.": "You will also collect fees earned from this position.", - "You will receive": "You will receive", - "You're about to send tokens to a special type of address - a smart contract. Double-check it's the address you intended to send to. If it's wrong, your tokens could be lost forever.": "You're about to send tokens to a special type of address - a smart contract. Double-check it's the address you intended to send to. If it's wrong, your tokens could be lost forever.", - "You're sending": "You're sending", - "Your account had insufficient funds to complete this swap.": "Your account had insufficient funds to complete this swap.", - "Your active V3 liquidity positions will appear here.": "Your active V3 liquidity positions will appear here.", - "Your balance": "Your balance", - "Your balances": "Your balances", - "Your connected network is unsupported.": "Your connected network is unsupported.", - "Your limit could not be fulfilled at this time. Please try again.": "Your limit could not be fulfilled at this time. Please try again.", - "Your limit price is {{pct}}% higher than market. Adjust your limit price to proceed.": "Your limit price is {{pct}}% higher than market. Adjust your limit price to proceed.", - "Your limit price is {{pct}}% lower than market. Adjust your limit price to proceed.": "Your limit price is {{pct}}% lower than market. Adjust your limit price to proceed.", - "Your onchain transactions and crypto purchases will appear here.": "Your onchain transactions and crypto purchases will appear here.", - "Your pool share:": "Your pool share:", - "Your position": "Your position", - "Your position has 0 liquidity, and is not earning fees.": "Your position has 0 liquidity, and is not earning fees.", - "Your position will appear here.": "Your position will appear here.", - "Your position will be 100% {{symbol}} at this price.": "Your position will be 100% {{symbol}} at this price.", - "Your position will be 100% composed of {{sym}} at this price": "Your position will be 100% composed of {{sym}} at this price", - "Your position will not earn fees or be used in trades until the market price moves into your range.": "Your position will not earn fees or be used in trades until the market price moves into your range.", - "Your positions": "Your positions", - "Your signature has expired.": "Your signature has expired.", - "Your swap could execute before cancellation is processed. Your network costs cannot be refunded. Do you wish to proceed?": "Your swap could execute before cancellation is processed. Your network costs cannot be refunded. Do you wish to proceed?", - "Your swap could not be executed. Please check your network connection and your slippage settings.": "Your swap could not be executed. Please check your network connection and your slippage settings.", - "Your swap could not be fulfilled at this time. Please try again.": "Your swap could not be fulfilled at this time. Please try again.", - "Your swap is expected to fail.": "Your swap is expected to fail.", - "Your swap was modified through your wallet. If this was a mistake, please cancel immediately or risk losing your funds.": "Your swap was modified through your wallet. If this was a mistake, please cancel immediately or risk losing your funds.", - "Your swaps could execute before cancellation is processed. Your network costs cannot be refunded. Do you wish to proceed?": "Your swaps could execute before cancellation is processed. Your network costs cannot be refunded. Do you wish to proceed?", - "Your tokens": "Your tokens", - "Your total pool tokens:": "Your total pool tokens:", - "Your transaction cost will be much higher as it includes the gas to create the pool.": "Your transaction cost will be much higher as it includes the gas to create the pool.", - "Your transaction may be frontrun and result in an unfavorable trade.": "Your transaction may be frontrun and result in an unfavorable trade.", - "Your transaction will revert if it is pending for more than this period of time.": "Your transaction will revert if it is pending for more than this period of time.", - "Your transaction will revert if the price changes unfavorably by more than this percentage.": "Your transaction will revert if the price changes unfavorably by more than this percentage.", - "Your V2 liquidity": "Your V2 liquidity", - "Your wallet is connected to the wrong network.": "Your wallet is connected to the wrong network.", - "Your wallet's current network is unsupported.": "Your wallet's current network is unsupported." + "weeks": "weeks" } diff --git a/apps/web/src/i18n/useTranslation.tsx b/apps/web/src/i18n/useTranslation.tsx new file mode 100644 index 00000000000..27b6cb41a4c --- /dev/null +++ b/apps/web/src/i18n/useTranslation.tsx @@ -0,0 +1,10 @@ +import i18n, { t } from 'i18next' +import { useTranslation as useTranslationOG } from 'react-i18next' + +export function useTranslation() { + if (process.env.NODE_ENV === 'test') { + return { i18n, t } + } + // eslint-disable-next-line react-hooks/rules-of-hooks + return useTranslationOG() +} diff --git a/apps/web/src/index.tsx b/apps/web/src/index.tsx index 1f13d5f2b06..9bcb20a4316 100644 --- a/apps/web/src/index.tsx +++ b/apps/web/src/index.tsx @@ -4,15 +4,17 @@ import '@reach/dialog/styles.css' import 'inter-ui' import 'polyfills' import 'tracing' +import './i18n' // ensure translations load before things /* eslint-enable prettier/prettier */ +import { getDeviceId } from '@amplitude/analytics-browser' import { ApolloProvider } from '@apollo/client' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { useWeb3React } from '@web3-react/core' -import { getDeviceId } from 'analytics' import { AssetActivityProvider } from 'graphql/data/apollo/AssetActivityProvider' import { TokenBalancesProvider } from 'graphql/data/apollo/TokenBalancesProvider' import { apolloClient } from 'graphql/data/apollo/client' +import { LanguageProvider } from 'i18n/LanguageProvider' import { BlockNumberProvider } from 'lib/hooks/useBlockNumber' import { MulticallUpdater } from 'lib/state/multicall' import { PropsWithChildren, StrictMode, useMemo } from 'react' @@ -30,7 +32,6 @@ import { getEnvName, isBrowserRouterEnabled } from 'utils/env' import { unregister as unregisterServiceWorker } from 'utils/serviceWorker' import { getCanonicalUrl } from 'utils/urlRoutes' import Web3Provider from './components/Web3Provider' -import { LanguageProvider } from './i18n' import App from './pages/App' import store from './state' import ApplicationUpdater from './state/application/updater' diff --git a/apps/web/src/lib/hooks/multicall.ts b/apps/web/src/lib/hooks/multicall.ts index 9636709223a..b34a95be6e2 100644 --- a/apps/web/src/lib/hooks/multicall.ts +++ b/apps/web/src/lib/hooks/multicall.ts @@ -1,8 +1,8 @@ import { ChainId } from '@uniswap/sdk-core' +import { useAccount } from 'hooks/useAccount' import useBlockNumber, { useMainnetBlockNumber } from 'lib/hooks/useBlockNumber' import multicall from 'lib/state/multicall' import { SkipFirst } from 'types/tuple' -import { useChainId } from 'wagmi' export { NEVER_RELOAD } from '@uniswap/redux-multicall' // re-export for convenience export type { CallStateResult } from '@uniswap/redux-multicall' // re-export for convenience @@ -36,7 +36,7 @@ export function useSingleContractMultipleData( } function useCallContext() { - const chainId = useChainId() + const { chainId } = useAccount() const latestBlock = useBlockNumber() return { chainId, latestBlock } } diff --git a/apps/web/src/lib/hooks/routing/clientSideSmartOrderRouter.ts b/apps/web/src/lib/hooks/routing/clientSideSmartOrderRouter.ts index e45799264f4..4c6a3656482 100644 --- a/apps/web/src/lib/hooks/routing/clientSideSmartOrderRouter.ts +++ b/apps/web/src/lib/hooks/routing/clientSideSmartOrderRouter.ts @@ -2,7 +2,7 @@ import { BigintIsh, ChainId, CurrencyAmount, Token, TradeType } from '@uniswap/s // This file is lazy-loaded, so the import of smart-order-router is intentional. // eslint-disable-next-line @typescript-eslint/no-restricted-imports import { AlphaRouter, AlphaRouterConfig } from '@uniswap/smart-order-router' -import { SupportedInterfaceChainId, getChainInfo, isSupportedChainId } from 'constants/chains' +import { SupportedInterfaceChainId, getChain, isSupportedChainId } from 'constants/chains' import { RPC_PROVIDERS } from 'constants/providers' import { nativeOnChain } from 'constants/tokens' import JSBI from 'jsbi' @@ -12,9 +12,11 @@ import { transformSwapRouteToGetQuoteResult } from 'utils/transformSwapRouteToGe const routers = new Map() export function getRouter(chainId: ChainId): AlphaRouter { const router = routers.get(chainId) - if (router) return router + if (router) { + return router + } - if (isSupportedChainId(chainId) && getChainInfo({ chainId }).supportsClientSideRouting) { + if (isSupportedChainId(chainId) && getChain({ chainId }).supportsClientSideRouting) { const provider = RPC_PROVIDERS[chainId as SupportedInterfaceChainId] const router = new AlphaRouter({ chainId, provider }) routers.set(chainId, router) diff --git a/apps/web/src/lib/hooks/routing/useRoutingAPIArguments.ts b/apps/web/src/lib/hooks/routing/useRoutingAPIArguments.ts index 6d2c8533ea4..096dd333745 100644 --- a/apps/web/src/lib/hooks/routing/useRoutingAPIArguments.ts +++ b/apps/web/src/lib/hooks/routing/useRoutingAPIArguments.ts @@ -1,11 +1,17 @@ import { SkipToken, skipToken } from '@reduxjs/toolkit/query/react' import { Protocol } from '@uniswap/router-sdk' -import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core' +import { ChainId, Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core' import { useMemo } from 'react' import { GetQuoteArgs, INTERNAL_ROUTER_PREFERENCE_PRICE, RouterPreference } from 'state/routing/types' import { currencyAddressForSwapQuote } from 'state/routing/utils' +import { Experiments } from 'uniswap/src/features/gating/experiments' import { FeatureFlags } from 'uniswap/src/features/gating/flags' -import { useFeatureFlag } from 'uniswap/src/features/gating/hooks' +import { useExperimentGroupName, useExperimentValue, useFeatureFlag } from 'uniswap/src/features/gating/hooks' + +enum ArbitrumXV2ExperimentGroup { + Test = 'Test', + Control = 'Control', +} /** * Returns query arguments for the Routing API query or undefined if the @@ -31,6 +37,12 @@ export function useRoutingAPIArguments({ }): GetQuoteArgs | SkipToken { const uniswapXForceSyntheticQuotes = useFeatureFlag(FeatureFlags.UniswapXSyntheticQuote) const isXv2 = useFeatureFlag(FeatureFlags.UniswapXv2) + const xv2ArbitrumEnabled = + useExperimentGroupName(Experiments.ArbitrumXV2OpenOrders) === ArbitrumXV2ExperimentGroup.Test + const isXv2Arbitrum = tokenIn?.chainId === ChainId.ARBITRUM_ONE && xv2ArbitrumEnabled + const priceImprovementBps = useExperimentValue(Experiments.ArbitrumXV2OpenOrders, 'priceImprovementBps', 0) + const forceOpenOrders = useExperimentValue(Experiments.ArbitrumXV2OpenOrders, 'forceOpenOrders', false) + const deadlineBufferSecs = useExperimentValue(Experiments.ArbitrumXV2OpenOrders, 'deadlineBufferSecs', 30) // Don't enable fee logic if this is a quote for pricing const sendPortionEnabled = routerPreference !== INTERNAL_ROUTER_PREFERENCE_PRICE @@ -56,6 +68,10 @@ export function useRoutingAPIArguments({ uniswapXForceSyntheticQuotes, sendPortionEnabled, isXv2, + isXv2Arbitrum, + priceImprovementBps, + forceOpenOrders, + deadlineBufferSecs, }, [ tokenIn, @@ -68,6 +84,10 @@ export function useRoutingAPIArguments({ uniswapXForceSyntheticQuotes, sendPortionEnabled, isXv2, + isXv2Arbitrum, + priceImprovementBps, + forceOpenOrders, + deadlineBufferSecs, ] ) } diff --git a/apps/web/src/lib/hooks/useApproval.ts b/apps/web/src/lib/hooks/useApproval.ts index 4c6192e9539..77c8d666b00 100644 --- a/apps/web/src/lib/hooks/useApproval.ts +++ b/apps/web/src/lib/hooks/useApproval.ts @@ -3,13 +3,13 @@ import type { TransactionResponse } from '@ethersproject/providers' import { InterfaceEventName } from '@uniswap/analytics-events' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' -import { sendAnalyticsEvent } from 'analytics' +import { useAccount } from 'hooks/useAccount' import { useTokenContract } from 'hooks/useContract' import { useTokenAllowance } from 'hooks/useTokenAllowance' import { getTokenAddress } from 'lib/utils/analytics' import { useCallback, useMemo } from 'react' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { calculateGasMargin } from 'utils/calculateGasMargin' -import { useChainId } from 'wagmi' export enum ApprovalState { UNKNOWN = 'UNKNOWN', @@ -30,10 +30,16 @@ function useApprovalStateForSpender( const pendingApproval = useIsPendingApproval(token, spender) return useMemo(() => { - if (!amountToApprove || !spender) return ApprovalState.UNKNOWN - if (amountToApprove.currency.isNative) return ApprovalState.APPROVED + if (!amountToApprove || !spender) { + return ApprovalState.UNKNOWN + } + if (amountToApprove.currency.isNative) { + return ApprovalState.APPROVED + } // we might not have enough data to know whether or not we need to approve - if (!tokenAllowance) return ApprovalState.UNKNOWN + if (!tokenAllowance) { + return ApprovalState.UNKNOWN + } // amountToApprove will be defined if tokenAllowance is return tokenAllowance.lessThan(amountToApprove) @@ -55,7 +61,7 @@ export function useApproval( | undefined > ] { - const chainId = useChainId() + const { chainId } = useAccount() const token = amountToApprove?.currency?.isToken ? amountToApprove.currency : undefined // check the current approval status diff --git a/apps/web/src/lib/hooks/useCurrencyBalance.ts b/apps/web/src/lib/hooks/useCurrencyBalance.ts index 784f5518f64..9b23b8c019b 100644 --- a/apps/web/src/lib/hooks/useCurrencyBalance.ts +++ b/apps/web/src/lib/hooks/useCurrencyBalance.ts @@ -5,8 +5,8 @@ import { useMultipleContractSingleData, useSingleContractMultipleData } from 'li import { useMemo } from 'react' import ERC20ABI from 'uniswap/src/abis/erc20.json' import { Erc20Interface } from 'uniswap/src/abis/types/Erc20' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import { isAddress } from 'utilities/src/addresses' import { nativeOnChain } from '../../constants/tokens' import { useInterfaceMulticall } from '../../hooks/useContract' @@ -17,7 +17,7 @@ import { useInterfaceMulticall } from '../../hooks/useContract' export function useNativeCurrencyBalances(uncheckedAddresses?: (string | undefined)[]): { [address: string]: CurrencyAmount | undefined } { - const chainId = useChainId() + const { chainId } = useAccount() const multicallContract = useInterfaceMulticall() const validAddressInputs: [string][] = useMemo( @@ -38,8 +38,9 @@ export function useNativeCurrencyBalances(uncheckedAddresses?: (string | undefin () => validAddressInputs.reduce<{ [address: string]: CurrencyAmount }>((memo, [address], i) => { const value = results?.[i]?.result?.[0] - if (value && chainId) + if (value && chainId) { memo[address] = CurrencyAmount.fromRawAmount(nativeOnChain(chainId), JSBI.BigInt(value.toString())) + } return memo }, {}), [validAddressInputs, chainId, results] @@ -56,7 +57,7 @@ export function useTokenBalancesWithLoadingIndicator( address?: string, tokens?: (Token | undefined)[] ): [{ [tokenAddress: string]: CurrencyAmount | undefined }, boolean] { - const chainId = useChainId() + const { chainId } = useAccount() const validatedTokens: Token[] = useMemo( () => tokens?.filter((t?: Token): t is Token => isAddress(t?.address) !== false && t?.chainId === chainId) ?? [], [chainId, tokens] @@ -104,7 +105,9 @@ export function useTokenBalance(account?: string, token?: Token): CurrencyAmount account, useMemo(() => [token], [token]) ) - if (!token) return undefined + if (!token) { + return undefined + } return tokenBalances[token.address] } @@ -121,7 +124,7 @@ export function useCurrencyBalances( [currencies] ) - const chainId = useChainId() + const { chainId } = useAccount() const tokenBalances = useTokenBalances(account, tokens) const containsETH: boolean = useMemo(() => currencies?.some((currency) => currency?.isNative) ?? false, [currencies]) const ethBalance = useNativeCurrencyBalances(useMemo(() => (containsETH ? [account] : []), [containsETH, account])) @@ -129,9 +132,15 @@ export function useCurrencyBalances( return useMemo( () => currencies?.map((currency) => { - if (!account || !currency || currency.chainId !== chainId) return undefined - if (currency.isToken) return tokenBalances[currency.address] - if (currency.isNative) return ethBalance[account] + if (!account || !currency || currency.chainId !== chainId) { + return undefined + } + if (currency.isToken) { + return tokenBalances[currency.address] + } + if (currency.isNative) { + return ethBalance[account] + } return undefined }) ?? [], [account, chainId, currencies, ethBalance, tokenBalances] diff --git a/apps/web/src/lib/hooks/useCurrencyLogoURIs.ts b/apps/web/src/lib/hooks/useCurrencyLogoURIs.ts index 473fb11c947..5875626096c 100644 --- a/apps/web/src/lib/hooks/useCurrencyLogoURIs.ts +++ b/apps/web/src/lib/hooks/useCurrencyLogoURIs.ts @@ -1,5 +1,5 @@ import { ChainId } from '@uniswap/sdk-core' -import { getChainInfo, isSupportedChainId } from 'constants/chains' +import { getChain, isSupportedChainId } from 'constants/chains' import { isSameAddress } from 'utilities/src/addresses' import EthereumLogo from '../../assets/images/ethereum-logo.png' @@ -27,7 +27,7 @@ export function getNativeLogoURI(chainId: ChainId = ChainId.MAINNET): string { } export function getTokenLogoURI(address: string, chainId: ChainId = ChainId.MAINNET): string | void { - const networkName = isSupportedChainId(chainId) ? getChainInfo({ chainId }).assetRepoNetworkName : undefined + const networkName = isSupportedChainId(chainId) ? getChain({ chainId }).assetRepoNetworkName : undefined if (isCelo(chainId) && isSameAddress(address, nativeOnChain(chainId).wrapped.address)) { return CeloLogo diff --git a/apps/web/src/lib/hooks/useInterval.ts b/apps/web/src/lib/hooks/useInterval.ts index 56ca8f84921..11be822f5d6 100644 --- a/apps/web/src/lib/hooks/useInterval.ts +++ b/apps/web/src/lib/hooks/useInterval.ts @@ -27,7 +27,9 @@ export default function useInterval(callback: () => void | Promise, delay: const promise = callback() // Defer the next interval until the current callback has resolved. - if (promise) await promise + if (promise) { + await promise + } } timeout = setTimeout(() => tick(delay), delay) diff --git a/apps/web/src/lib/hooks/useTokenList/filtering.ts b/apps/web/src/lib/hooks/useTokenList/filtering.ts index bfe421bf4b6..a77b4a508dc 100644 --- a/apps/web/src/lib/hooks/useTokenList/filtering.ts +++ b/apps/web/src/lib/hooks/useTokenList/filtering.ts @@ -18,7 +18,9 @@ export function getTokenFilter(query: string): (tok .split(/\s+/) .filter((s) => s.length > 0) - if (queryParts.length === 0) return alwaysTrue + if (queryParts.length === 0) { + return alwaysTrue + } const match = (s: string): boolean => { const parts = s diff --git a/apps/web/src/lib/hooks/useTokenList/sorting.ts b/apps/web/src/lib/hooks/useTokenList/sorting.ts index 2f55063b337..9412e8fd698 100644 --- a/apps/web/src/lib/hooks/useTokenList/sorting.ts +++ b/apps/web/src/lib/hooks/useTokenList/sorting.ts @@ -24,7 +24,9 @@ function tokenComparator(balances: TokenBalances, a: Token, b: Token) { const bAddress = b.isNative ? 'ETH' : b.address?.toLowerCase() // Sorts by balances const balanceComparison = balanceComparator(balances[aAddress]?.usdValue, balances[bAddress]?.usdValue) - if (balanceComparison !== 0) return balanceComparison + if (balanceComparison !== 0) { + return balanceComparison + } // Sorts by symbol if (a.symbol && b.symbol) { @@ -62,7 +64,7 @@ export function getSortedPortfolioTokens( address, tokenBalance.token?.decimals, tokenBalance.token?.symbol, - tokenBalance.token?.name + tokenBalance.token?.project?.name ?? tokenBalance.token?.name ) return portfolioToken diff --git a/apps/web/src/lib/hooks/useTokenList/utils.ts b/apps/web/src/lib/hooks/useTokenList/utils.ts index 71b50d23a6c..54ce22a8fdc 100644 --- a/apps/web/src/lib/hooks/useTokenList/utils.ts +++ b/apps/web/src/lib/hooks/useTokenList/utils.ts @@ -13,7 +13,9 @@ const mapCache = typeof WeakMap !== 'undefined' ? new WeakMap>((map, info) => { diff --git a/apps/web/src/lib/state/multicall.tsx b/apps/web/src/lib/state/multicall.tsx index 07aa691d7b4..f72e17b1a2a 100644 --- a/apps/web/src/lib/state/multicall.tsx +++ b/apps/web/src/lib/state/multicall.tsx @@ -1,10 +1,10 @@ import { createMulticall, ListenerOptions } from '@uniswap/redux-multicall' import { ChainId } from '@uniswap/sdk-core' import { CHAIN_INFO, useSupportedChainId } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' import { useInterfaceMulticall, useMainnetInterfaceMulticall } from 'hooks/useContract' import useBlockNumber, { useMainnetBlockNumber } from 'lib/hooks/useBlockNumber' import { useMemo } from 'react' -import { useChainId } from 'wagmi' const multicall = createMulticall() @@ -13,7 +13,7 @@ export default multicall const MAINNET_LISTENER_OPTIONS = { blocksPerFetch: 1 } export function MulticallUpdater() { - const chainId = useChainId() + const { chainId } = useAccount() const supportedChain = useSupportedChainId(chainId) const latestBlockNumber = useBlockNumber() const contract = useInterfaceMulticall() diff --git a/apps/web/src/lib/utils/analytics.ts b/apps/web/src/lib/utils/analytics.ts index cae251f2300..8c095ba404c 100644 --- a/apps/web/src/lib/utils/analytics.ts +++ b/apps/web/src/lib/utils/analytics.ts @@ -5,7 +5,9 @@ import { isClassicTrade, isSubmittableTrade, isUniswapXTrade } from 'state/routi import { computeRealizedPriceImpact } from 'utils/prices' export const getDurationUntilTimestampSeconds = (futureTimestampInSecondsSinceEpoch?: number): number | undefined => { - if (!futureTimestampInSecondsSinceEpoch) return undefined + if (!futureTimestampInSecondsSinceEpoch) { + return undefined + } return futureTimestampInSecondsSinceEpoch - new Date().getTime() / 1000 } @@ -30,8 +32,12 @@ export const getPriceUpdateBasisPoints = ( } function getEstimatedNetworkFee(trade: InterfaceTrade) { - if (isClassicTrade(trade)) return trade.gasUseEstimateUSD - if (isUniswapXTrade(trade)) return trade.classicGasUseEstimateUSD + if (isClassicTrade(trade)) { + return trade.gasUseEstimateUSD + } + if (isUniswapXTrade(trade)) { + return trade.classicGasUseEstimateUSD + } return undefined } @@ -95,7 +101,9 @@ export const formatSwapSignedAnalyticsEventProperties = ({ }) function getQuoteMethod(trade: InterfaceTrade) { - if (isUniswapXTrade(trade)) return QuoteMethod.ROUTING_API + if (isUniswapXTrade(trade)) { + return QuoteMethod.ROUTING_API + } return trade.quoteMethod } diff --git a/apps/web/src/lib/utils/contenthashToUri.ts b/apps/web/src/lib/utils/contenthashToUri.ts index 2c667f108f2..9c9f3045607 100644 --- a/apps/web/src/lib/utils/contenthashToUri.ts +++ b/apps/web/src/lib/utils/contenthashToUri.ts @@ -4,7 +4,9 @@ import { decode, toB58String } from 'multihashes' export function hexToUint8Array(hex: string): Uint8Array { hex = hex.startsWith('0x') ? hex.substr(2) : hex - if (hex.length % 2 !== 0) throw new Error('hex must have length that is multiple of 2') + if (hex.length % 2 !== 0) { + throw new Error('hex must have length that is multiple of 2') + } const arr = new Uint8Array(hex.length / 2) for (let i = 0; i < arr.length; i++) { arr[i] = parseInt(hex.substr(i * 2, 2), 16) diff --git a/apps/web/src/lib/utils/parseENSAddress.ts b/apps/web/src/lib/utils/parseENSAddress.ts index d331ce80b3a..3e45b5ff4e4 100644 --- a/apps/web/src/lib/utils/parseENSAddress.ts +++ b/apps/web/src/lib/utils/parseENSAddress.ts @@ -2,6 +2,8 @@ const ENS_NAME_REGEX = /^(([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+)eth(\/.*)?$/ export default function parseENSAddress(ensAddress: string): { ensName: string; ensPath?: string } | undefined { const match = ensAddress.match(ENS_NAME_REGEX) - if (!match) return undefined + if (!match) { + return undefined + } return { ensName: `${match[1].toLowerCase()}eth`, ensPath: match[4] } } diff --git a/apps/web/src/nft/components/bag/Bag.tsx b/apps/web/src/nft/components/bag/Bag.tsx index 2d285f804ff..22c160437c9 100644 --- a/apps/web/src/nft/components/bag/Bag.tsx +++ b/apps/web/src/nft/components/bag/Bag.tsx @@ -1,5 +1,5 @@ import { NFTEventName } from '@uniswap/analytics-events' -import { sendAnalyticsEvent } from 'analytics' +import { useIsMobile } from 'hooks/screenSize' import { useIsNftDetailsPage, useIsNftPage, useIsNftProfilePage } from 'hooks/useIsNftPage' import { Trans } from 'i18n' import { Box } from 'nft/components/Box' @@ -13,8 +13,7 @@ import { formatAssetEventProperties, recalculateBagUsingPooledAssets } from 'nft import { useCallback, useEffect, useMemo, useState } from 'react' import styled from 'styled-components' import { Z_INDEX } from 'theme/zIndex' - -import { useIsMobile } from 'hooks/screenSize' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import * as styles from './Bag.css' import { BagContent } from './BagContent' import { BagHeader } from './BagHeader' @@ -127,7 +126,9 @@ const Bag = () => { }, [setBagExpanded]) useEffect(() => { - if (bagIsLocked && !isModalOpen) setModalIsOpen(true) + if (bagIsLocked && !isModalOpen) { + setModalIsOpen(true) + } }, [bagIsLocked, isModalOpen]) const hasAssetsToShow = itemsInBag.length > 0 @@ -178,7 +179,7 @@ const Bag = () => { }) }} > - Continue + )} diff --git a/apps/web/src/nft/components/bag/BagContent.tsx b/apps/web/src/nft/components/bag/BagContent.tsx index 2e80c0db8c7..32223a22568 100644 --- a/apps/web/src/nft/components/bag/BagContent.tsx +++ b/apps/web/src/nft/components/bag/BagContent.tsx @@ -1,12 +1,13 @@ import { NFTEventName } from '@uniswap/analytics-events' -import { sendAnalyticsEvent, Trace } from 'analytics' import { useIsMobile } from 'hooks/screenSize' -import { BagRow, PriceChangeBagRow, UnavailableAssetsHeaderRow } from 'nft/components/bag/BagRow' import { Column } from 'nft/components/Flex' +import { BagRow, PriceChangeBagRow, UnavailableAssetsHeaderRow } from 'nft/components/bag/BagRow' import { useBag, useNativeUsdPrice } from 'nft/hooks' import { BagItemStatus, BagStatus } from 'nft/types' import { formatAssetEventProperties, recalculateBagUsingPooledAssets } from 'nft/utils' import { useEffect, useMemo } from 'react' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' export const BagContent = () => { const bagStatus = useBag((s) => s.bagStatus) @@ -45,16 +46,20 @@ export const BagContent = () => { const hasAssetsInReview = priceChangedAssets.length > 0 const hasAssets = itemsInBag.length > 0 - if (hasAssetsInReview) + if (hasAssetsInReview) { sendAnalyticsEvent(NFTEventName.NFT_BUY_BAG_CHANGED, { usd_value: ethUsdPrice, - bag_quantity: itemsInBag, + bag_quantity: itemsInBag.length, ...formatAssetEventProperties(priceChangedAssets), }) + } if (bagStatus === BagStatus.IN_REVIEW && !hasAssetsInReview) { - if (hasAssets) setBagStatus(BagStatus.CONFIRM_REVIEW) - else setBagStatus(BagStatus.ADDING_TO_BAG) + if (hasAssets) { + setBagStatus(BagStatus.CONFIRM_REVIEW) + } else { + setBagStatus(BagStatus.ADDING_TO_BAG) + } } if (bagStatus === BagStatus.CONFIRM_REVIEW && !hasAssets) { @@ -67,13 +72,13 @@ export const BagContent = () => { 0 || unavailableAssets.length > 0 ? 'flex' : 'none'}> {unavailableAssets.length > 0 && ( - Fetching price... + ) } @@ -245,7 +245,7 @@ const FiatValue = ({ {priceImpact && ( <> - + @@ -470,7 +470,7 @@ export const BagFooter = ({ setModalIsOpen, eventProperties }: BagFooterProps) = {isSupportedChain && ( <> - Pay with + { @@ -491,7 +491,7 @@ export const BagFooter = ({ setModalIsOpen, eventProperties }: BagFooterProps) = - Total + - {warningText} {helperText} @@ -528,7 +528,7 @@ export const BagFooter = ({ setModalIsOpen, eventProperties }: BagFooterProps) = {isPending && } {buttonText} - + - {isProfilePage ? Sell : Bag} + + {isProfilePage ? : } + {numberOfAssets > 0 && ( <> {numberOfAssets} - Clear all + )} diff --git a/apps/web/src/nft/components/bag/BagRow.tsx b/apps/web/src/nft/components/bag/BagRow.tsx index eb8a330733a..421b2e95541 100644 --- a/apps/web/src/nft/components/bag/BagRow.tsx +++ b/apps/web/src/nft/components/bag/BagRow.tsx @@ -291,7 +291,9 @@ export const UnavailableAssetsHeaderRow = ({ return () => clearInterval(intervalId) }, [timeLeft, clearUnavailableAssets, didOpenUnavailableAssets, setDidOpenUnavailableAssets]) - if (!assets || assets.length === 0) return null + if (!assets || assets.length === 0) { + return null + } const moreThanOneUnavailable = assets.length > 1 const isShowingAssets = isOpen || !moreThanOneUnavailable diff --git a/apps/web/src/nft/components/bag/ButtonStates.tsx b/apps/web/src/nft/components/bag/ButtonStates.tsx index e195577c361..fc6251d8525 100644 --- a/apps/web/src/nft/components/bag/ButtonStates.tsx +++ b/apps/web/src/nft/components/bag/ButtonStates.tsx @@ -43,7 +43,7 @@ export function getBuyButtonStateData( ): BuyButtonStateData { const defaultBuyButtonState: BuyButtonStateData = { handleClick: () => undefined, - buttonText: Something went wrong, + buttonText: , disabled: true, warningText: undefined, warningTextColor: theme.deprecated_accentWarning, @@ -58,89 +58,89 @@ export function getBuyButtonStateData( ...defaultBuyButtonState, handleClick: handleClickOverride ?? (() => undefined), disabled: false, - buttonText: Connect wallet, + buttonText: , }, [BuyButtonStates.NOT_SUPPORTED_CHAIN]: { ...defaultBuyButtonState, handleClick: handleClickOverride ?? (() => undefined), - buttonText: Switch networks, + buttonText: , disabled: false, - warningText: Wrong network, + warningText: , }, [BuyButtonStates.INSUFFICIENT_BALANCE]: { ...defaultBuyButtonState, - buttonText: Pay, - warningText: Insufficient funds, + buttonText: , + warningText: , }, [BuyButtonStates.ERROR]: { ...defaultBuyButtonState, - warningText: Something went wrong. Please try again., + warningText: , }, [BuyButtonStates.IN_WALLET_CONFIRMATION]: { ...defaultBuyButtonState, - buttonText: Proceed in wallet, + buttonText: , }, [BuyButtonStates.PROCESSING_TRANSACTION]: { ...defaultBuyButtonState, - buttonText: Transaction pending, + buttonText: , }, [BuyButtonStates.FETCHING_TOKEN_ROUTE]: { ...defaultBuyButtonState, - buttonText: Fetching route, + buttonText: , }, [BuyButtonStates.INVALID_TOKEN_ROUTE]: { ...defaultBuyButtonState, - buttonText: Pay, + buttonText: , }, [BuyButtonStates.NO_TOKEN_ROUTE_FOUND]: { ...defaultBuyButtonState, - buttonText: Insufficient liquidity, + buttonText: , buttonColor: theme.surface3, buttonTextColor: theme.neutral1, - helperText: Insufficient pool liquidity to complete transaction, + helperText: , }, [BuyButtonStates.LOADING_ALLOWANCE]: { ...defaultBuyButtonState, - buttonText: Loading allowance, + buttonText: , }, [BuyButtonStates.IN_WALLET_ALLOWANCE_APPROVAL]: { ...defaultBuyButtonState, - buttonText: Approve in your wallet, + buttonText: , }, [BuyButtonStates.PROCESSING_APPROVAL]: { ...defaultBuyButtonState, - buttonText: Approval pending, + buttonText: , }, [BuyButtonStates.REQUIRE_APPROVAL]: { ...defaultBuyButtonState, disabled: false, handleClick: handleClickOverride ?? (() => undefined), - helperText: An approval is needed to use this token. , - buttonText: Approve, + helperText: , + buttonText: , }, [BuyButtonStates.CONFIRM_UPDATED_PRICE]: { ...defaultBuyButtonState, handleClick: handleClickOverride ?? (() => undefined), disabled: false, warningTextColor: theme.accent1, - warningText: Price updated, - buttonText: Pay, + warningText: , + buttonText: , }, [BuyButtonStates.PRICE_IMPACT_HIGH]: { ...defaultBuyButtonState, handleClick: handleClickOverride ?? (() => undefined), disabled: false, buttonColor: priceImpact ? priceImpact.priceImpactSeverity.color : defaultBuyButtonState.buttonColor, - helperText: Price impact warning, + helperText: , helperTextColor: priceImpact ? priceImpact.priceImpactSeverity.color : defaultBuyButtonState.helperTextColor, - buttonText: Pay Anyway, + buttonText: , }, [BuyButtonStates.PAY]: { ...defaultBuyButtonState, handleClick: handleClickOverride ?? (() => undefined), disabled: false, - buttonText: Pay, - helperText: usingPayWithAnyToken ? Refunds for unavailable items will be given in ETH : undefined, + buttonText: , + helperText: usingPayWithAnyToken ? : undefined, }, } diff --git a/apps/web/src/nft/components/card/icons.tsx b/apps/web/src/nft/components/card/icons.tsx index a52ecaa3b8f..0fab24deb43 100644 --- a/apps/web/src/nft/components/card/icons.tsx +++ b/apps/web/src/nft/components/card/icons.tsx @@ -148,7 +148,7 @@ export const Suspicious = () => { - Blocked on OpenSea + } placement="top" diff --git a/apps/web/src/nft/components/card/index.tsx b/apps/web/src/nft/components/card/index.tsx index 9f412e8d331..14ff0f68821 100644 --- a/apps/web/src/nft/components/card/index.tsx +++ b/apps/web/src/nft/components/card/index.tsx @@ -91,7 +91,9 @@ export const NftCard = ({ detailsHref={onCardClick ? undefined : detailsHref(asset)} testId={testId} onClick={() => { - if (bagExpanded) setBagExpanded({ bagExpanded: false }) + if (bagExpanded) { + setBagExpanded({ bagExpanded: false }) + } onCardClick?.() sendAnalyticsEvent?.() }} diff --git a/apps/web/src/nft/components/card/media.tsx b/apps/web/src/nft/components/card/media.tsx index 3c9c8ae9c6b..a614187e25b 100644 --- a/apps/web/src/nft/components/card/media.tsx +++ b/apps/web/src/nft/components/card/media.tsx @@ -247,9 +247,9 @@ const NoContentContainer = ({ height }: { height?: number }) => ( <> - Content not +
- available yet +
diff --git a/apps/web/src/nft/components/card/utils.tsx b/apps/web/src/nft/components/card/utils.tsx index 33494e6113f..71bb137ea56 100644 --- a/apps/web/src/nft/components/card/utils.tsx +++ b/apps/web/src/nft/components/card/utils.tsx @@ -27,8 +27,12 @@ function getAssetMediaUrl(asset: GenieAsset | WalletAsset) { } export function detailsHref(asset: GenieAsset | WalletAsset) { - if ('address' in asset) return `/nfts/asset/${asset.address}/${asset.tokenId}?origin=collection` - if ('asset_contract' in asset) return `/nfts/asset/${asset.asset_contract.address}/${asset.tokenId}?origin=profile` + if ('address' in asset) { + return `/nfts/asset/${asset.address}/${asset.tokenId}?origin=collection` + } + if ('asset_contract' in asset) { + return `/nfts/asset/${asset.asset_contract.address}/${asset.tokenId}?origin=profile` + } return '/nfts/profile' } diff --git a/apps/web/src/nft/components/collection/ActivityCells.tsx b/apps/web/src/nft/components/collection/ActivityCells.tsx index ede18eeee01..e252039a7af 100644 --- a/apps/web/src/nft/components/collection/ActivityCells.tsx +++ b/apps/web/src/nft/components/collection/ActivityCells.tsx @@ -1,6 +1,5 @@ import { InterfacePageName, NFTEventName } from '@uniswap/analytics-events' import { ChainId } from '@uniswap/sdk-core' -import { sendAnalyticsEvent, useTrace } from 'analytics' import { MouseoverTooltip } from 'components/Tooltip' import { Trans } from 'i18n' import { Box } from 'nft/components/Box' @@ -34,10 +33,11 @@ import { NftMarketplace, OrderStatus, } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { shortenAddress } from 'utilities/src/addresses' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { NumberType, useFormatter } from 'utils/formatNumbers' import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink' - import * as styles from './Activity.css' const AddressLink = styled(ExternalLink)` @@ -62,7 +62,9 @@ const AddressLink = styled(ExternalLink)` ` const isPurchasableOrder = (orderStatus?: OrderStatus, marketplace?: string): boolean => { - if (!marketplace || !orderStatus) return false + if (!marketplace || !orderStatus) { + return false + } const purchasableMarkets = Object.keys(NftMarketplace).map((market) => market.toLowerCase()) const validOrder = orderStatus === OrderStatus.Valid @@ -72,18 +74,18 @@ const isPurchasableOrder = (orderStatus?: OrderStatus, marketplace?: string): bo const formatListingStatus = (status: OrderStatus, orderIsPurchasable: boolean, isSelected: boolean): ReactNode => { if (orderIsPurchasable) { - return isSelected ? Remove : Add to bag + return isSelected ? : } switch (status) { case OrderStatus.Executed: - return Sold + return case OrderStatus.Cancelled: - return Cancelled + return case OrderStatus.Expired: - return Expired + return case OrderStatus.Valid: - return Unavailable + return default: return null } @@ -139,7 +141,7 @@ export const BuyCell = ({ e.preventDefault() isSelected ? removeAsset([asset]) : selectAsset([asset]) !isSelected && !cartExpanded && !isMobile && toggleCart() - !isSelected && sendAnalyticsEvent(NFTEventName.NFT_BUY_ADDED, { eventProperties }) + !isSelected && sendAnalyticsEvent(NFTEventName.NFT_BUY_ADDED, eventProperties) }} disabled={!orderIsPurchasable} > @@ -332,7 +334,9 @@ const Ranking = ({ rarity, collectionName, rarityVerified }: RankingProps) => { const { formatNumber } = useFormatter() const rank = (rarity as TokenRarity).rank || (rarity as Rarity).providers?.[0].rank - if (!rank) return null + if (!rank) { + return null + } return ( diff --git a/apps/web/src/nft/components/collection/ActivitySwitcher.tsx b/apps/web/src/nft/components/collection/ActivitySwitcher.tsx index 8a021b6e050..dfc251cab01 100644 --- a/apps/web/src/nft/components/collection/ActivitySwitcher.tsx +++ b/apps/web/src/nft/components/collection/ActivitySwitcher.tsx @@ -1,10 +1,9 @@ -import { BrowserEvent, InterfaceElementName, NFTEventName } from '@uniswap/analytics-events' -import { TraceEvent } from 'analytics' +import { InterfaceElementName, NFTEventName } from '@uniswap/analytics-events' import { Box } from 'nft/components/Box' import { Row } from 'nft/components/Flex' import { useIsCollectionLoading } from 'nft/hooks' import styled from 'styled-components' - +import Trace from 'uniswap/src/features/telemetry/Trace' import * as styles from './ActivitySwitcher.css' const BaseActivityContainer = styled(Row)` @@ -39,10 +38,10 @@ export const ActivitySwitcher = ({ > Items - Activity - + )} diff --git a/apps/web/src/nft/components/collection/CollectionAsset.tsx b/apps/web/src/nft/components/collection/CollectionAsset.tsx index 615b2aec730..5a0935c5ef6 100644 --- a/apps/web/src/nft/components/collection/CollectionAsset.tsx +++ b/apps/web/src/nft/components/collection/CollectionAsset.tsx @@ -1,12 +1,13 @@ import { BigNumber } from '@ethersproject/bignumber' import { InterfacePageName, NFTEventName } from '@uniswap/analytics-events' -import { sendAnalyticsEvent, useTrace } from 'analytics' import { Trans } from 'i18n' import { NftCard, NftCardDisplayProps } from 'nft/components/card' import { Ranking as RankingContainer, Suspicious as SuspiciousContainer } from 'nft/components/card/icons' import { useBag } from 'nft/hooks' import { GenieAsset, UniformAspectRatio } from 'nft/types' import { useCallback, useMemo } from 'react' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { NumberType, useFormatter } from 'utils/formatNumbers' interface CollectionAssetProps { @@ -80,9 +81,9 @@ export const CollectionAsset = ({ secondaryInfo: notForSale ? '' : `${formatEther({ input: asset.priceInfo.ETHPrice, type: NumberType.NFTToken })} ETH`, - selectedInfo: Remove from bag, - notSelectedInfo: Add to bag, - disabledInfo: Not listed, + selectedInfo: , + notSelectedInfo: , + disabledInfo: , } }, [ asset.name, diff --git a/apps/web/src/nft/components/collection/CollectionNfts.tsx b/apps/web/src/nft/components/collection/CollectionNfts.tsx index 35461c7792c..e44f961213a 100644 --- a/apps/web/src/nft/components/collection/CollectionNfts.tsx +++ b/apps/web/src/nft/components/collection/CollectionNfts.tsx @@ -1,26 +1,26 @@ import { BigNumber } from '@ethersproject/bignumber' import { parseEther } from '@ethersproject/units' -import { BrowserEvent, InterfaceElementName, NFTEventName } from '@uniswap/analytics-events' -import { TraceEvent } from 'analytics' +import { InterfaceElementName, NFTEventName } from '@uniswap/analytics-events' import clsx from 'clsx' import { OpacityHoverState } from 'components/Common' import { ASSET_PAGE_SIZE, AssetFetcherParams, useNftAssets } from 'graphql/data/nft/Asset' import { useIsMobile, useScreenSize } from 'hooks/screenSize' +import { useAccount } from 'hooks/useAccount' import useDebounce from 'hooks/useDebounce' import { AnimatedBox, Box } from 'nft/components/Box' +import { Center, Column, Row } from 'nft/components/Flex' import { CollectionSearch, FilterButton } from 'nft/components/collection' import { CollectionAsset } from 'nft/components/collection/CollectionAsset' import * as styles from 'nft/components/collection/CollectionNfts.css' import { SortDropdown } from 'nft/components/common/SortDropdown' -import { Center, Column, Row } from 'nft/components/Flex' import { SweepIcon } from 'nft/components/icons' import { bodySmall, buttonTextMedium, headlineMedium } from 'nft/css/common.css' import { loadingAsset } from 'nft/css/loading.css' import { CollectionFilters, - initialCollectionFilterState, SortBy, SortByQueries, + initialCollectionFilterState, useBag, useCollectionFilters, useFiltersExpanded, @@ -31,10 +31,10 @@ import { DropDownOption, GenieAsset, GenieCollection, - isPooledMarket, Markets, UniformAspectRatio, UniformAspectRatios, + isPooledMarket, } from 'nft/types' import { calcPoolPrice, @@ -56,13 +56,12 @@ import { NftMarketplace, NftStandard, } from 'uniswap/src/data/graphql/uniswap-data-api/__generated__/types-and-hooks' -import { useChainId } from 'wagmi' - +import Trace from 'uniswap/src/features/telemetry/Trace' import { LoadingAssets } from './CollectionAssetLoading' import { MARKETPLACE_ITEMS } from './MarketplaceSelect' -import { ClearAllButton } from './shared' import { Sweep } from './Sweep' import { TraitChip } from './TraitChip' +import { ClearAllButton } from './shared' interface CollectionNftsProps { contractAddress: string @@ -223,7 +222,7 @@ export const getSortDropdownOptions = (setSortBy: (sortBy: SortBy) => void, hasR } export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerified }: CollectionNftsProps) => { - const chainId = useChainId() + const { chainId } = useAccount() const traits = useCollectionFilters((state) => state.traits) const minPrice = useCollectionFilters((state) => state.minPrice) const maxPrice = useCollectionFilters((state) => state.maxPrice) @@ -383,7 +382,9 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie }, [contractAddress]) const assets = useMemo(() => { - if (!collectionAssets) return null + if (!collectionAssets) { + return null + } return collectionAssets.map((asset) => ( { - if (hasErc1155s) return + if (hasErc1155s) { + return + } if (!sweepIsOpen) { scrollToTop() - if (!bagExpanded && !isMobile) toggleBag() + if (!bagExpanded && !isMobile) { + toggleBag() + } } setSweepOpen(!sweepIsOpen) }, [bagExpanded, hasErc1155s, isMobile, sweepIsOpen, toggleBag]) @@ -495,11 +500,11 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie > - { - if (bagExpanded && !screenSize['xl']) toggleBag() + if (bagExpanded && !screenSize['xl']) { + toggleBag() + } setFiltersExpanded(!isFiltersExpanded) }} /> - + diff --git a/apps/web/src/nft/components/collection/MarketplaceSelect.tsx b/apps/web/src/nft/components/collection/MarketplaceSelect.tsx index b8eab41c561..4d48cbe3b19 100644 --- a/apps/web/src/nft/components/collection/MarketplaceSelect.tsx +++ b/apps/web/src/nft/components/collection/MarketplaceSelect.tsx @@ -1,9 +1,8 @@ import { NFTEventName, NFTFilterTypes } from '@uniswap/analytics-events' -import { sendAnalyticsEvent } from 'analytics' import clsx from 'clsx' import { Box } from 'nft/components/Box' -import * as styles from 'nft/components/collection/Filters.css' import { Column, Row } from 'nft/components/Flex' +import * as styles from 'nft/components/collection/Filters.css' import { ChevronUpIcon } from 'nft/components/icons' import { subheadSmall } from 'nft/css/common.css' import { useCollectionFilters } from 'nft/hooks/useCollectionFilters' @@ -12,7 +11,7 @@ import { getMarketplaceIcon } from 'nft/utils' import { FormEvent, useEffect, useMemo, useReducer, useState } from 'react' import styled from 'styled-components' import { ThemedText } from 'theme/components' - +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { Checkbox } from '../layout/Checkbox' const FilterItemWrapper = styled(Row)` diff --git a/apps/web/src/nft/components/collection/PriceRange.tsx b/apps/web/src/nft/components/collection/PriceRange.tsx index 12ea4c60977..6e1e050a2eb 100644 --- a/apps/web/src/nft/components/collection/PriceRange.tsx +++ b/apps/web/src/nft/components/collection/PriceRange.tsx @@ -1,7 +1,6 @@ import 'rc-slider/assets/index.css' import { NFTEventName, NFTFilterTypes } from '@uniswap/analytics-events' -import { sendAnalyticsEvent } from 'analytics' import { Box } from 'nft/components/Box' import { Row } from 'nft/components/Flex' import { NumericInput } from 'nft/components/layout/Input' @@ -15,6 +14,7 @@ import { FocusEventHandler, FormEvent, useEffect, useState } from 'react' import { useLocation } from 'react-router-dom' import styled, { useTheme } from 'styled-components' import { darkDeprecatedTheme } from 'theme/deprecatedColors' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import * as styles from './PriceRange.css' import { TraitsHeader } from './TraitsHeader' @@ -54,8 +54,9 @@ export const PriceRange = () => { const handleBlur: FocusEventHandler = (e) => { e.currentTarget.placeholder = placeholderText setPlaceholderText('') - if (minPrice || maxPrice) + if (minPrice || maxPrice) { sendAnalyticsEvent(NFTEventName.NFT_FILTER_SELECTED, { filter_type: NFTFilterTypes.PRICE_RANGE }) + } } const updateMinPriceRange = (v: FormEvent) => { @@ -106,7 +107,9 @@ export const PriceRange = () => { } const handleSliderLogic = (minMax: number | Array) => { - if (typeof minMax === 'number') return + if (typeof minMax === 'number') { + return + } const [newMin, newMax] = minMax diff --git a/apps/web/src/nft/components/collection/Sweep.tsx b/apps/web/src/nft/components/collection/Sweep.tsx index 9d5d13fb534..cb8614de991 100644 --- a/apps/web/src/nft/components/collection/Sweep.tsx +++ b/apps/web/src/nft/components/collection/Sweep.tsx @@ -195,9 +195,15 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => { let jointCollections: GenieAsset[] = [] - if (sudoSwapAssets) jointCollections = [...jointCollections, ...sudoSwapAssets] - if (nftxAssets) jointCollections = [...jointCollections, ...nftxAssets] - if (nft20Assets) jointCollections = [...jointCollections, ...nft20Assets] + if (sudoSwapAssets) { + jointCollections = [...jointCollections, ...sudoSwapAssets] + } + if (nftxAssets) { + jointCollections = [...jointCollections, ...nftxAssets] + } + if (nft20Assets) { + jointCollections = [...jointCollections, ...nft20Assets] + } const sudoSwapAssetsInJointCollections = jointCollections.filter( (sweepAsset) => sweepAsset.marketplace === Markets.Sudoswap && !sweepAsset.susFlag @@ -267,7 +273,9 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => { }, [itemsInBag, contractAddress]) useEffect(() => { - if (sweepItemsInBag.length === 0) setSweepAmount('') + if (sweepItemsInBag.length === 0) { + setSweepAmount('') + } }, [sweepItemsInBag]) useEffect(() => { @@ -282,7 +290,9 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => { const handleSweep = (value: number) => { if (sortedAssets) { if (isItemsToggled) { - if (sweepItemsInBag.length === 0 && value > 0) setBagExpanded({ bagExpanded: true }) + if (sweepItemsInBag.length === 0 && value > 0) { + setBagExpanded({ bagExpanded: true }) + } if (sweepItemsInBag.length < value) { addAssetsToBag(sortedAssets.slice(sweepItemsInBag.length, value), true) @@ -307,7 +317,9 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => { } if (wishAssets.length > 0) { - if (sweepItemsInBag.length === 0) setBagExpanded({ bagExpanded: true }) + if (sweepItemsInBag.length === 0) { + setBagExpanded({ bagExpanded: true }) + } addAssetsToBag(wishAssets, true) } } else { @@ -335,8 +347,9 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => { if (typeof value === 'number') { if (sortedAssets) { if (isItemsToggled) { - if (Math.floor(value) !== Math.floor(sweepAmount !== '' ? parseFloat(sweepAmount) : 0)) + if (Math.floor(value) !== Math.floor(sweepAmount !== '' ? parseFloat(sweepAmount) : 0)) { handleSweep(Math.floor(value)) + } setSweepAmount(value < 1 ? '' : value.toString()) } else { handleSweep(value) @@ -369,7 +382,7 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => { - Sweep + @@ -468,7 +481,9 @@ function useSweepFetcherParams( return { contractAddress: '', traits: [], markets: [] } } } - if (!markets.includes(market)) return { contractAddress: '', traits: [], markets: [] } + if (!markets.includes(market)) { + return { contractAddress: '', traits: [], markets: [] } + } } switch (market) { diff --git a/apps/web/src/nft/components/collection/TraitSelect.tsx b/apps/web/src/nft/components/collection/TraitSelect.tsx index db10036516d..c0bf4f74b81 100644 --- a/apps/web/src/nft/components/collection/TraitSelect.tsx +++ b/apps/web/src/nft/components/collection/TraitSelect.tsx @@ -1,5 +1,4 @@ import { NFTEventName, NFTFilterTypes } from '@uniswap/analytics-events' -import { sendAnalyticsEvent } from 'analytics' import useDebounce from 'hooks/useDebounce' import { Box } from 'nft/components/Box' import { Column, Row } from 'nft/components/Flex' @@ -11,7 +10,7 @@ import { scrollToTop } from 'nft/utils/scrollToTop' import { CSSProperties, FormEvent, MouseEvent, useCallback, useEffect, useMemo, useState } from 'react' import AutoSizer from 'react-virtualized-auto-sizer' import { FixedSizeList } from 'react-window' - +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { Input } from '../layout/Input' import * as styles from './Filters.css' import { TraitsHeader } from './TraitsHeader' diff --git a/apps/web/src/nft/components/collection/TransactionCompleteModal.tsx b/apps/web/src/nft/components/collection/TransactionCompleteModal.tsx index acb0458ca89..a2ecaadc60e 100644 --- a/apps/web/src/nft/components/collection/TransactionCompleteModal.tsx +++ b/apps/web/src/nft/components/collection/TransactionCompleteModal.tsx @@ -1,9 +1,9 @@ import { formatEther as ethersFormatEther } from '@ethersproject/units' import { InterfaceModalName, NFTEventName } from '@uniswap/analytics-events' -import { Trace, useTrace } from 'analytics' import clsx from 'clsx' import { OpacityHoverState } from 'components/Common' import { UniIcon } from 'components/Logo/UniIcon' +import { useIsMobile } from 'hooks/screenSize' import { Trans } from 'i18n' import { Box } from 'nft/components/Box' import { Row } from 'nft/components/Flex' @@ -17,10 +17,10 @@ import { generateTweetForPurchase, getSuccessfulImageSize, parseTransactionRespo import { formatAssetEventProperties } from 'nft/utils/formatEventProperties' import { useEffect, useMemo, useRef, useState } from 'react' import styled from 'styled-components' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { NumberType, useFormatter } from 'utils/formatNumbers' import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink' - -import { useIsMobile } from 'hooks/screenSize' import * as styles from './TransactionCompleteModal.css' const TWITTER_WIDTH = 560 @@ -101,7 +101,8 @@ const TxCompleteModal = () => { {/* Successfully purchased NFTs */} {showPurchasedModal && ( { ...formatAssetEventProperties(nftsPurchased), ...trace, }} - shouldLogImpression >

- Complete! +

- Uniswap has granted your wish! +

@@ -175,7 +175,7 @@ const TxCompleteModal = () => {
- View on Etherscan + @@ -187,7 +187,8 @@ const TxCompleteModal = () => { /* Showing both purchases & refunds */ (showPurchasedModal ? ( { transaction_hash: txHash, ...trace, }} - shouldLogImpression > { ) : ( // Only showing when all assets are unavailable diff --git a/apps/web/src/nft/components/collection/UnavailableCollectionPage.tsx b/apps/web/src/nft/components/collection/UnavailableCollectionPage.tsx index 8f980d4ea7d..0cb9e3455ac 100644 --- a/apps/web/src/nft/components/collection/UnavailableCollectionPage.tsx +++ b/apps/web/src/nft/components/collection/UnavailableCollectionPage.tsx @@ -31,13 +31,13 @@ export function UnavailableCollectionPage({ isBlocked }: { isBlocked?: boolean } data-testid="alert-icon" /> - This collection is blocked + - Return to NFT Explore + - Learn why + ) @@ -46,10 +46,10 @@ export function UnavailableCollectionPage({ isBlocked }: { isBlocked?: boolean } return ( - No collection assets exist at this address + - Return to NFT Explore + ) diff --git a/apps/web/src/nft/components/details/AssetActivity.tsx b/apps/web/src/nft/components/details/AssetActivity.tsx index 2c2dea2c1a3..47202c1ea42 100644 --- a/apps/web/src/nft/components/details/AssetActivity.tsx +++ b/apps/web/src/nft/components/details/AssetActivity.tsx @@ -97,19 +97,19 @@ const ActivityTable = ({ children }: { children: ReactNode }) => { - Event + - Price + - By + - To + - Time + @@ -157,7 +157,9 @@ const AssetActivity = ({ events }: { events?: ActivityEvent[] }) => { const formattedPrice = price ? formatNumberOrString({ input: parseFloat(price), type: NumberType.NFTToken }) : null - if (!eventType) return null + if (!eventType) { + return null + } return ( diff --git a/apps/web/src/nft/components/details/AssetPriceDetails.tsx b/apps/web/src/nft/components/details/AssetPriceDetails.tsx index 4f4aff4839f..7058728e8fa 100644 --- a/apps/web/src/nft/components/details/AssetPriceDetails.tsx +++ b/apps/web/src/nft/components/details/AssetPriceDetails.tsx @@ -1,6 +1,5 @@ import { NFTEventName } from '@uniswap/analytics-events' import { useWeb3React } from '@web3-react/core' -import { sendAnalyticsEvent, useTrace } from 'analytics' import { OpacityHoverState } from 'components/Common' import { Share } from 'components/Icons/Share' import { useNftBalance } from 'graphql/data/nft/NftBalance' @@ -12,7 +11,9 @@ import { useMemo } from 'react' import { Link, useNavigate } from 'react-router-dom' import styled, { css, useTheme } from 'styled-components' import { ExternalLink, ThemedText } from 'theme/components' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { shortenAddress } from 'utilities/src/addresses' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { NumberType, useFormatter } from 'utils/formatNumbers' const TWITTER_WIDTH = 560 diff --git a/apps/web/src/nft/components/explore/Banner.tsx b/apps/web/src/nft/components/explore/Banner.tsx index c04ed3897aa..156f0473b2d 100644 --- a/apps/web/src/nft/components/explore/Banner.tsx +++ b/apps/web/src/nft/components/explore/Banner.tsx @@ -104,7 +104,9 @@ const Banner = () => { const [activeCollectionIdx, setActiveCollectionIdx] = useState(0) const onToggleNextSlide = useCallback( (direction: number) => { - if (!collections) return + if (!collections) { + return + } setActiveCollectionIdx((idx) => calculateCardIndex(idx + direction, collections.length)) }, [collections] diff --git a/apps/web/src/nft/components/explore/CarouselCard.tsx b/apps/web/src/nft/components/explore/CarouselCard.tsx index bc867dbb0da..571aeb8d31d 100644 --- a/apps/web/src/nft/components/explore/CarouselCard.tsx +++ b/apps/web/src/nft/components/explore/CarouselCard.tsx @@ -240,7 +240,9 @@ export const CarouselCard = ({ collection, onClick }: CarouselCardProps) => { const { data: gqlCollection, loading } = useCollection(collection.address ?? '') const { formatNumber } = useFormatter() - if (loading) return + if (loading) { + return + } return ( diff --git a/apps/web/src/nft/components/explore/Cells/Cells.tsx b/apps/web/src/nft/components/explore/Cells/Cells.tsx index a83fdbf7c82..f7de33ea892 100644 --- a/apps/web/src/nft/components/explore/Cells/Cells.tsx +++ b/apps/web/src/nft/components/explore/Cells/Cells.tsx @@ -101,8 +101,12 @@ export const DiscreteNumberCell = ({ value }: CellProps) => { } const getDenominatedValue = (denomination: Denomination, inWei: boolean, value?: number, usdPrice?: number) => { - if (denomination === Denomination.ETH) return value - if (usdPrice && value) return usdPrice * (inWei ? parseFloat(formatEther(value)) : value) + if (denomination === Denomination.ETH) { + return value + } + if (usdPrice && value) { + return usdPrice * (inWei ? parseFloat(formatEther(value)) : value) + } return undefined } diff --git a/apps/web/src/nft/components/explore/CollectionTable.tsx b/apps/web/src/nft/components/explore/CollectionTable.tsx index 1fea17d4eff..ac208aea976 100644 --- a/apps/web/src/nft/components/explore/CollectionTable.tsx +++ b/apps/web/src/nft/components/explore/CollectionTable.tsx @@ -19,8 +19,12 @@ export enum ColumnHeaders { const VOLUME_CHANGE_MAX_VALUE = 9999 const compareFloats = (a?: number, b?: number): 1 | -1 => { - if (!a) return -1 - if (!b) return 1 + if (!a) { + return -1 + } + if (!b) { + return 1 + } return Math.round(a * 100000) >= Math.round(b * 100000) ? 1 : -1 } diff --git a/apps/web/src/nft/components/explore/Table.tsx b/apps/web/src/nft/components/explore/Table.tsx index d68bab12739..ea988a54b01 100644 --- a/apps/web/src/nft/components/explore/Table.tsx +++ b/apps/web/src/nft/components/explore/Table.tsx @@ -1,16 +1,15 @@ -import { BrowserEvent, InterfaceElementName, NFTEventName } from '@uniswap/analytics-events' -import { TraceEvent } from 'analytics' +import { InterfaceElementName, NFTEventName } from '@uniswap/analytics-events' import { ArrowChangeDown } from 'components/Icons/ArrowChangeDown' import { ArrowChangeUp } from 'components/Icons/ArrowChangeUp' import { LoadingBubble } from 'components/Tokens/loading' import { useIsMobile, useWindowSize } from 'hooks/screenSize' +import { useAccount } from 'hooks/useAccount' import { useEffect } from 'react' import { useNavigate } from 'react-router-dom' import { Column, ColumnInstance, HeaderGroup, IdType, useSortBy, useTable } from 'react-table' import styled, { useTheme } from 'styled-components' import { ThemedText } from 'theme/components' -import { useChainId } from 'wagmi' - +import Trace from 'uniswap/src/features/telemetry/Trace' import { Box } from '../../components/Box' import { CollectionTableColumn } from '../../types' import { ColumnHeaders } from './CollectionTable' @@ -102,7 +101,7 @@ export function Table>({ ...props }: TableProps) { const theme = useTheme() - const chainId = useChainId() + const { chainId } = useAccount() const { width } = useWindowSize() const isMobile = useIsMobile() @@ -127,7 +126,9 @@ export function Table>({ const navigate = useNavigate() useEffect(() => { - if (!width) return + if (!width) { + return + } if (width <= theme.breakpoint.sm) { setHiddenColumns(smallHiddenColumns) @@ -186,9 +187,9 @@ export function Table>({ prepareRow(row) return ( - >({ ) })} - + ) })} diff --git a/apps/web/src/nft/components/explore/TrendingCollections.tsx b/apps/web/src/nft/components/explore/TrendingCollections.tsx index a643da2db93..675441b7cdf 100644 --- a/apps/web/src/nft/components/explore/TrendingCollections.tsx +++ b/apps/web/src/nft/components/explore/TrendingCollections.tsx @@ -124,7 +124,9 @@ const TrendingCollections = () => { denomination: isEthToggled ? Denomination.ETH : Denomination.USD, usdPrice: ethUsdPrice, })) - } else return [] as CollectionTableColumn[] + } else { + return [] as CollectionTableColumn[] + } }, [trendingCollections, trendingCollectionsAreLoading, isEthToggled, ethUsdPrice]) return ( diff --git a/apps/web/src/nft/components/profile/list/ListPage.tsx b/apps/web/src/nft/components/profile/list/ListPage.tsx index 87b64587d33..d660665966c 100644 --- a/apps/web/src/nft/components/profile/list/ListPage.tsx +++ b/apps/web/src/nft/components/profile/list/ListPage.tsx @@ -1,7 +1,9 @@ import { InterfaceModalName, NFTEventName } from '@uniswap/analytics-events' -import { sendAnalyticsEvent, useTrace } from 'analytics' import Column from 'components/Column' import Row from 'components/Row' +import { useIsMobile } from 'hooks/screenSize' +import { useAccount } from 'hooks/useAccount' +import { useEthersSigner } from 'hooks/useEthersSigner' import { useStablecoinValue } from 'hooks/useStablecoinPrice' import { Trans } from 'i18n' import useNativeCurrency from 'lib/hooks/useNativeCurrency' @@ -23,11 +25,9 @@ import styled from 'styled-components' import { BREAKPOINTS } from 'theme' import { ThemedText } from 'theme/components' import { Z_INDEX } from 'theme/zIndex' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { NumberType, useFormatter } from 'utils/formatNumbers' - -import { useIsMobile } from 'hooks/screenSize' -import { useEthersSigner } from 'hooks/useEthersSigner' -import { useAccount } from 'wagmi' import { ListModal } from './Modal/ListModal' import { NFTListingsGrid } from './NFTListingsGrid' import { SelectMarketplacesDropdown } from './SelectMarketplacesDropdown' @@ -233,7 +233,9 @@ export const ListPage = () => { } const startListingFlow = async () => { - if (!signer) return + if (!signer) { + return + } sendAnalyticsEvent(NFTEventName.NFT_SELL_START_LISTING, { ...startListingEventProperties }) // for all unique collection, marketplace combos -> approve collections @@ -252,11 +254,11 @@ export const ListPage = () => { const BannerText = isMobile ? ( - Receive + ) : ( - You receive + ) @@ -269,12 +271,12 @@ export const ListPage = () => { setSellPageState(ProfilePageStateType.VIEWING)} /> - My NFTs + - Sell NFTs + diff --git a/apps/web/src/nft/components/profile/list/ListingButton.tsx b/apps/web/src/nft/components/profile/list/ListingButton.tsx index 2456de9e47e..d4e7e5ddafd 100644 --- a/apps/web/src/nft/components/profile/list/ListingButton.tsx +++ b/apps/web/src/nft/components/profile/list/ListingButton.tsx @@ -1,5 +1,5 @@ import { BaseButton } from 'components/Button' -import { Plural, t, Trans } from 'i18n' +import { Plural, Trans, t } from 'i18n' import { BelowFloorWarningModal } from 'nft/components/profile/list/Modal/BelowFloorWarningModal' import { useSellAsset } from 'nft/hooks' import { useMemo, useState } from 'react' @@ -61,16 +61,21 @@ export const ListingButton = ({ onClick }: { onClick: () => void }) => { setIssues(foundIssues) !foundIssues && showResolveIssues && toggleShowResolveIssues() // Only show Resolve Issue text if there was a user submitted error (ie not when page loads with no prices set) - if ((missingExpiration || overMaxExpiration || listingsAboveSellOrderFloor.length) && !showResolveIssues) + if ((missingExpiration || overMaxExpiration || listingsAboveSellOrderFloor.length) && !showResolveIssues) { toggleShowResolveIssues() + } return [listingsMissingPrice, listingsBelowFloor] }, [sellAssets, setIssues, showResolveIssues, toggleShowResolveIssues]) const warningWrappedClick = () => { - if (issues) !showResolveIssues && toggleShowResolveIssues() - else if (listingsBelowFloor.length) setShowWarning(true) - else onClick() + if (issues) { + !showResolveIssues && toggleShowResolveIssues() + } else if (listingsBelowFloor.length) { + setShowWarning(true) + } else { + onClick() + } } return ( @@ -83,13 +88,13 @@ export const ListingButton = ({ onClick }: { onClick: () => void }) => { {showResolveIssues ? ( ) : listingsMissingPrice.length && !isMobile ? ( - Set prices to continue + ) : ( - Start listing + )} diff --git a/apps/web/src/nft/components/profile/list/MarketplaceRow.tsx b/apps/web/src/nft/components/profile/list/MarketplaceRow.tsx index cea3edba912..7f98a17cdef 100644 --- a/apps/web/src/nft/components/profile/list/MarketplaceRow.tsx +++ b/apps/web/src/nft/components/profile/list/MarketplaceRow.tsx @@ -144,7 +144,9 @@ export const MarketplaceRow = ({ const setPrice = useCallback( (price?: number) => { showGlobalPrice ? setGlobalPrice(price) : setListPrice(price) - for (const marketplace of selectedMarkets) setAssetListPrice(asset, price, marketplace) + for (const marketplace of selectedMarkets) { + setAssetListPrice(asset, price, marketplace) + } }, [asset, selectedMarkets, setAssetListPrice, setGlobalPrice, showGlobalPrice] ) @@ -241,7 +243,7 @@ export const MarketplaceRow = ({ > - {fees > 0 ? `${formatDelta(fees)}${selectedMarkets.length > 1 ? t`max` : ''}` : '--%'} + {fees > 0 ? `${formatDelta(fees)}${selectedMarkets.length > 1 ? t('max') : ''}` : '--%'} diff --git a/apps/web/src/nft/components/profile/list/Modal/BelowFloorWarningModal.tsx b/apps/web/src/nft/components/profile/list/Modal/BelowFloorWarningModal.tsx index f66297bf327..89162961f3b 100644 --- a/apps/web/src/nft/components/profile/list/Modal/BelowFloorWarningModal.tsx +++ b/apps/web/src/nft/components/profile/list/Modal/BelowFloorWarningModal.tsx @@ -1,6 +1,6 @@ import { ButtonPrimary } from 'components/Button' import Column from 'components/Column' -import { Plural, t, Trans } from 'i18n' +import { Plural, Trans, t } from 'i18n' import { Portal } from 'nft/components/common/Portal' import { Overlay } from 'nft/components/modals/Overlay' import { Listing, WalletAsset } from 'nft/types' @@ -100,28 +100,28 @@ export const BelowFloorWarningModal = ({ - Low listing price +   - below the collection’s floor price. Are you sure you want to continue? + - Continue + - Edit listings + diff --git a/apps/web/src/nft/components/profile/list/Modal/ContentRow.tsx b/apps/web/src/nft/components/profile/list/Modal/ContentRow.tsx index d6a77407665..7efaf21545e 100644 --- a/apps/web/src/nft/components/profile/list/Modal/ContentRow.tsx +++ b/apps/web/src/nft/components/profile/list/Modal/ContentRow.tsx @@ -151,7 +151,7 @@ export const ContentRow = ({ /> ) : row.status === ListingStatus.SIGNING ? ( - Proceed in wallet + ) : row.status === ListingStatus.APPROVED ? ( @@ -160,7 +160,11 @@ export const ContentRow = ({ - {row.status === ListingStatus.FAILED ? Failed : Rejected} + {row.status === ListingStatus.FAILED ? ( + + ) : ( + + )} ) @@ -170,10 +174,10 @@ export const ContentRow = ({ {failed && ( removeRow(row)}> - Remove + - Retry + )} diff --git a/apps/web/src/nft/components/profile/list/Modal/ListModal.tsx b/apps/web/src/nft/components/profile/list/Modal/ListModal.tsx index 780e2697bda..8940d73fce4 100644 --- a/apps/web/src/nft/components/profile/list/Modal/ListModal.tsx +++ b/apps/web/src/nft/components/profile/list/Modal/ListModal.tsx @@ -1,5 +1,6 @@ import { InterfaceModalName, NFTEventName } from '@uniswap/analytics-events' -import { Trace, sendAnalyticsEvent, useTrace } from 'analytics' +import { useAccount } from 'hooks/useAccount' +import { useEthersWeb3Provider } from 'hooks/useEthersProvider' import { useStablecoinValue } from 'hooks/useStablecoinPrice' import { Trans } from 'i18n' import useNativeCurrency from 'lib/hooks/useNativeCurrency' @@ -15,10 +16,10 @@ import styled from 'styled-components' import { BREAKPOINTS } from 'theme' import { ThemedText } from 'theme/components' import { Z_INDEX } from 'theme/zIndex' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { NumberType, useFormatter } from 'utils/formatNumbers' - -import { useEthersWeb3Provider } from 'hooks/useEthersProvider' -import { useAccount } from 'wagmi' import { TitleRow } from '../shared' import { ListModalSection, Section } from './ListModalSection' import { SuccessScreen } from './SuccessScreen' @@ -93,7 +94,9 @@ export const ListModal = ({ overlayClick }: { overlayClick: () => void }) => { ) const signListings = async () => { - if (!signer || !provider) return + if (!signer || !provider) { + return + } // sign listings for (const listing of listings) { await signListingRow(listing, signer, provider, getLooksRareNonce, setLooksRareNonce, setListingStatusAndCallback) @@ -135,7 +138,7 @@ export const ListModal = ({ overlayClick }: { overlayClick: () => void }) => { <> - List NFTs + diff --git a/apps/web/src/nft/components/profile/list/Modal/ListModalSection.tsx b/apps/web/src/nft/components/profile/list/Modal/ListModalSection.tsx index 5dffb75cb81..943ef5fa899 100644 --- a/apps/web/src/nft/components/profile/list/Modal/ListModalSection.tsx +++ b/apps/web/src/nft/components/profile/list/Modal/ListModalSection.tsx @@ -85,9 +85,11 @@ export const ListModalSection = ({ sectionType, active, content, toggleSection } // collections if (isCollectionApprovalSection) { const collectionRow = row as CollectionRow - for (const asset of sellAssets) - if (asset.asset_contract.address === collectionRow.collectionAddress) + for (const asset of sellAssets) { + if (asset.asset_contract.address === collectionRow.collectionAddress) { removeAssetMarketplace(asset, collectionRow.marketplace) + } + } } // listings else { @@ -107,13 +109,14 @@ export const ListModalSection = ({ sectionType, active, content, toggleSection } {isCollectionApprovalSection ? ( <> - Approve  - + +   + ) : ( <> - Sign  {content.length} {' '} - +  {content.length} {' '} + )} @@ -129,11 +132,9 @@ export const ListModalSection = ({ sectionType, active, content, toggleSection } {isCollectionApprovalSection && ( - Why is a transaction required? + - Listing an NFT requires a one-time marketplace approval for each NFT collection.} - > + }> diff --git a/apps/web/src/nft/components/profile/list/Modal/SuccessScreen.tsx b/apps/web/src/nft/components/profile/list/Modal/SuccessScreen.tsx index f27c8950aaa..a852079bcfa 100644 --- a/apps/web/src/nft/components/profile/list/Modal/SuccessScreen.tsx +++ b/apps/web/src/nft/components/profile/list/Modal/SuccessScreen.tsx @@ -14,8 +14,8 @@ import styled, { css, useTheme } from 'styled-components' import { BREAKPOINTS } from 'theme' import { ThemedText } from 'theme/components' import { NumberType, useFormatter } from 'utils/formatNumbers' -import { useChainId } from 'wagmi' +import { useAccount } from 'hooks/useAccount' import { TitleRow } from '../shared' const SuccessImage = styled.img<{ numImages: number }>` @@ -79,7 +79,7 @@ export const SuccessScreen = ({ overlayClick }: { overlayClick: () => void }) => const theme = useTheme() const { formatNumberOrString } = useFormatter() const sellAssets = useSellAsset((state) => state.sellAssets) - const chainId = useChainId() + const { chainId } = useAccount() const nativeCurrency = useNativeCurrency(chainId) const { formatCurrencyAmount } = useFormatter() @@ -91,7 +91,8 @@ export const SuccessScreen = ({ overlayClick }: { overlayClick: () => void }) => <> - Successfully listed {sellAssets.length > 1 ? ` ${sellAssets.length} ` : ''} + +  {sellAssets.length > 1 ? ` ${sellAssets.length} ` : ''} NFT{pluralize(sellAssets.length)}! @@ -107,7 +108,7 @@ export const SuccessScreen = ({ overlayClick }: { overlayClick: () => void }) => - Proceeds if sold + @@ -125,7 +126,7 @@ export const SuccessScreen = ({ overlayClick }: { overlayClick: () => void }) => window.location.reload()}> - Return to My NFTs + @@ -135,7 +136,7 @@ export const SuccessScreen = ({ overlayClick }: { overlayClick: () => void }) => color={theme.deprecated_accentTextLightPrimary} fill={theme.deprecated_accentTextLightPrimary} /> - Share on Twitter + diff --git a/apps/web/src/nft/components/profile/list/NFTListingsGrid.tsx b/apps/web/src/nft/components/profile/list/NFTListingsGrid.tsx index 749a78ac3dc..3dbc5eaf67d 100644 --- a/apps/web/src/nft/components/profile/list/NFTListingsGrid.tsx +++ b/apps/web/src/nft/components/profile/list/NFTListingsGrid.tsx @@ -193,16 +193,16 @@ export const NFTListingsGrid = ({ selectedMarkets }: { selectedMarkets: ListingM let prompt switch (globalPriceMethod) { case SetPriceMethod.CUSTOM: - prompt = Custom + prompt = break case SetPriceMethod.FLOOR_PRICE: - prompt = Floor price + prompt = break case SetPriceMethod.LAST_PRICE: - prompt = Last price + prompt = break case SetPriceMethod.SAME_PRICE: - prompt = Same price + prompt = break default: break @@ -212,18 +212,18 @@ export const NFTListingsGrid = ({ selectedMarkets }: { selectedMarkets: ListingM - NFT + - Floor + - Last + - Price + {prompt} @@ -237,10 +237,10 @@ export const NFTListingsGrid = ({ selectedMarkets }: { selectedMarkets: ListingM - Fees + - You receive + diff --git a/apps/web/src/nft/components/profile/list/PriceTextInput.tsx b/apps/web/src/nft/components/profile/list/PriceTextInput.tsx index 47a90e9bd12..e06592bdc3a 100644 --- a/apps/web/src/nft/components/profile/list/PriceTextInput.tsx +++ b/apps/web/src/nft/components/profile/list/PriceTextInput.tsx @@ -78,10 +78,10 @@ const getWarningMessage = (warning: WarningType) => { let message = <> switch (warning) { case WarningType.BELOW_FLOOR: - message = below floor price. + message = break case WarningType.ALREADY_LISTED: - message = Already listed at + message = break } return message @@ -175,7 +175,11 @@ export const PriceTextInput = ({ setWarningType(WarningType.NONE) }} > - {warningType === WarningType.BELOW_FLOOR ? Dismiss : Remove item} + {warningType === WarningType.BELOW_FLOOR ? ( + + ) : ( + + )} )} diff --git a/apps/web/src/nft/components/profile/list/RoyaltyTooltip.tsx b/apps/web/src/nft/components/profile/list/RoyaltyTooltip.tsx index 85391cb3c81..a55a5ba1374 100644 --- a/apps/web/src/nft/components/profile/list/RoyaltyTooltip.tsx +++ b/apps/web/src/nft/components/profile/list/RoyaltyTooltip.tsx @@ -67,7 +67,7 @@ export const RoyaltyTooltip = ({ {getMarketplaceIcon(market.name, '16')} {market.name}  - fee + {formatDelta(market.fee)} @@ -77,14 +77,14 @@ export const RoyaltyTooltip = ({ - Max creator royalties + {maxRoyalty}% - Max fees + {fees ? formatNumberOrString({ input: fees, type: NumberType.NFTToken }) : '-'} ETH diff --git a/apps/web/src/nft/components/profile/list/SelectMarketplacesDropdown.tsx b/apps/web/src/nft/components/profile/list/SelectMarketplacesDropdown.tsx index f5c842f6105..ae36998e553 100644 --- a/apps/web/src/nft/components/profile/list/SelectMarketplacesDropdown.tsx +++ b/apps/web/src/nft/components/profile/list/SelectMarketplacesDropdown.tsx @@ -41,7 +41,9 @@ const MarketplaceRow = ({ market, setSelectedMarkets, selectedMarkets }: Marketp const [hovered, toggleHovered] = useReducer((s) => !s, false) const toggleSelected = () => { - if (selectedMarkets.length === 1 && isSelected) return + if (selectedMarkets.length === 1 && isSelected) { + return + } isSelected ? setSelectedMarkets(selectedMarkets.filter((selected: ListingMarket) => selected !== market)) : setSelectedMarkets([...selectedMarkets, market]) diff --git a/apps/web/src/nft/components/profile/list/SetDurationModal.tsx b/apps/web/src/nft/components/profile/list/SetDurationModal.tsx index 72b20d38e91..044ae1e801f 100644 --- a/apps/web/src/nft/components/profile/list/SetDurationModal.tsx +++ b/apps/web/src/nft/components/profile/list/SetDurationModal.tsx @@ -145,16 +145,16 @@ export const SetDurationModal = () => { let prompt switch (duration) { case Duration.hour: - prompt = + prompt = break case Duration.day: - prompt = + prompt = break case Duration.week: - prompt = + prompt = break case Duration.month: - prompt = + prompt = break default: break @@ -163,9 +163,13 @@ export const SetDurationModal = () => { useEffect(() => { const expiration = convertDurationToExpiration(parseFloat(amount), duration) - if (expiration * 1000 - Date.now() < ms(`60s`) || isNaN(expiration)) setErrorState(ErrorState.empty) - else if (expiration * 1000 - Date.now() > ms(`180d`)) setErrorState(ErrorState.overMax) - else setErrorState(ErrorState.valid) + if (expiration * 1000 - Date.now() < ms(`60s`) || isNaN(expiration)) { + setErrorState(ErrorState.empty) + } else if (expiration * 1000 - Date.now() > ms(`180d`)) { + setErrorState(ErrorState.overMax) + } else { + setErrorState(ErrorState.valid) + } setGlobalExpiration(expiration) }, [amount, duration, setGlobalExpiration]) diff --git a/apps/web/src/nft/components/profile/list/utils.ts b/apps/web/src/nft/components/profile/list/utils.ts index 7c6f2fb1b41..b2a5af55411 100644 --- a/apps/web/src/nft/components/profile/list/utils.ts +++ b/apps/web/src/nft/components/profile/list/utils.ts @@ -151,7 +151,9 @@ export function useHandleGlobalPriceToggle( useEffect(() => { let price: number | undefined if (globalOverride) { - if (!listPrice) setListPrice(globalPrice) + if (!listPrice) { + setListPrice(globalPrice) + } price = globalPrice } else { price = listPrice @@ -177,8 +179,9 @@ export function useSyncPriceWithGlobalMethod( } else if (globalPriceMethod === SetPriceMethod.LAST_PRICE) { setListPrice(asset.lastPrice) setGlobalPrice(asset.lastPrice) - } else if (globalPriceMethod === SetPriceMethod.SAME_PRICE) + } else if (globalPriceMethod === SetPriceMethod.SAME_PRICE) { listPrice && !globalPrice ? setGlobalPrice(listPrice) : setListPrice(globalPrice) + } setGlobalOverride(false) // eslint-disable-next-line react-hooks/exhaustive-deps @@ -195,13 +198,15 @@ export function useUpdateInputAndWarnings( setWarningType(WarningType.NONE) const price = listPrice ?? 0 inputRef.current.value = `${price}` - if (price < (asset?.floorPrice ?? 0) && price > 0) setWarningType(WarningType.BELOW_FLOOR) - else if ( + if (price < (asset?.floorPrice ?? 0) && price > 0) { + setWarningType(WarningType.BELOW_FLOOR) + } else if ( asset.floor_sell_order_price && price >= asset.floor_sell_order_price && asset.asset_contract.tokenType !== NftStandard.Erc1155 - ) + ) { setWarningType(WarningType.ALREADY_LISTED) + } }, [ asset.asset_contract.tokenType, asset?.floorPrice, @@ -243,15 +248,20 @@ export const findListingIssues = (sellAssets: WalletAsset[]) => { for (const asset of sellAssets) { if (asset.newListings) { for (const listing of asset.newListings) { - if (!listing.price) listingsMissingPrice.push([asset, listing]) - else if (listing.price < (asset?.floorPrice ?? 0) * BELOW_FLOOR_PRICE_THRESHOLD && !listing.overrideFloorPrice) + if (!listing.price) { + listingsMissingPrice.push([asset, listing]) + } else if ( + listing.price < (asset?.floorPrice ?? 0) * BELOW_FLOOR_PRICE_THRESHOLD && + !listing.overrideFloorPrice + ) { listingsBelowFloor.push([asset, listing]) - else if ( + } else if ( asset.floor_sell_order_price && listing.price >= asset.floor_sell_order_price && asset.asset_contract.tokenType !== NftStandard.Erc1155 - ) + ) { listingsAboveSellOrderFloor.push([asset, listing]) + } } } } diff --git a/apps/web/src/nft/components/profile/view/EmptyWalletContent.tsx b/apps/web/src/nft/components/profile/view/EmptyWalletContent.tsx index ff4abeda013..7e79d9e1664 100644 --- a/apps/web/src/nft/components/profile/view/EmptyWalletContent.tsx +++ b/apps/web/src/nft/components/profile/view/EmptyWalletContent.tsx @@ -55,28 +55,28 @@ type EmptyWalletContent = { type EmptyWalletContentType = 'nft' | 'token' | 'activity' | 'pool' const EMPTY_WALLET_CONTENT: { [key in EmptyWalletContentType]: EmptyWalletContent } = { nft: { - title: No NFTs yet, - subtitle: Buy or transfer NFTs to this wallet to get started., - actionText: Explore NFTs, + title: , + subtitle: , + actionText: , urlPath: '/nfts', icon: , }, token: { - title: No tokens yet, - subtitle: Buy or transfer tokens to this wallet to get started., - actionText: Explore tokens, + title: , + subtitle: , + actionText: , urlPath: '/tokens', icon: , }, activity: { - title: No activity yet, - subtitle: Your onchain transactions and crypto purchases will appear here., + title: , + subtitle: , icon: , }, pool: { - title: No pools yet, - subtitle: Open a new position or create a pool to get started., - actionText: + New position, + title: , + subtitle: , + actionText: , urlPath: '/pool', icon: , }, diff --git a/apps/web/src/nft/components/profile/view/FilterSidebar.tsx b/apps/web/src/nft/components/profile/view/FilterSidebar.tsx index f179e2ff1eb..974a6cd6cbf 100644 --- a/apps/web/src/nft/components/profile/view/FilterSidebar.tsx +++ b/apps/web/src/nft/components/profile/view/FilterSidebar.tsx @@ -182,7 +182,9 @@ const CollectionSelect = ({ }, [collectionSearchText, collections]) const itemKey = useCallback((index: number, data: WalletCollection[]) => { - if (!data) return index + if (!data) { + return index + } const collection = data[index] return `${collection.address}_${index}` }, []) diff --git a/apps/web/src/nft/components/profile/view/ProfilePage.tsx b/apps/web/src/nft/components/profile/view/ProfilePage.tsx index e1a18a15259..9b3df5d1655 100644 --- a/apps/web/src/nft/components/profile/view/ProfilePage.tsx +++ b/apps/web/src/nft/components/profile/view/ProfilePage.tsx @@ -186,7 +186,9 @@ const ProfilePageNfts = ({ }, }) - if (loading) return + if (loading) { + return + } return ( @@ -286,7 +288,9 @@ const CollectionFilterItem = ({ collection?: WalletCollection setCollectionFilters: (address: string) => void }) => { - if (!collection) return null + if (!collection) { + return null + } return ( x.tokenId === asset.tokenId && x.asset_contract.address === asset.asset_contract.address ) && !isMobile - ) + ) { toggleCart() + } } const isDisabled = asset.susFlag @@ -68,9 +70,9 @@ export const ViewMyNftsAsset = ({ primaryInfo: !!asset.asset_contract.name && asset.asset_contract.name, primaryInfoIcon: asset.collectionIsVerified && , secondaryInfo: asset.name || asset.tokenId ? asset.name ?? `#${asset.tokenId}` : null, - selectedInfo: Remove from bag, - notSelectedInfo: List for sale, - disabledInfo: Unavailable for listing, + selectedInfo: , + notSelectedInfo: , + disabledInfo: , } }, [asset.asset_contract.name, asset.collectionIsVerified, asset.name, asset.tokenId]) @@ -84,7 +86,9 @@ export const ViewMyNftsAsset = ({ unselectAsset={() => handleSelect(true)} onButtonClick={toggleSelect} onCardClick={() => { - if (!hideDetails) navigate(detailsHref(asset)) + if (!hideDetails) { + navigate(detailsHref(asset)) + } }} mediaShouldBePlaying={mediaShouldBePlaying} setCurrentTokenPlayingMedia={setCurrentTokenPlayingMedia} diff --git a/apps/web/src/nft/css/atoms.ts b/apps/web/src/nft/css/atoms.ts index 35f03c201b8..b2e95ddfa0a 100644 --- a/apps/web/src/nft/css/atoms.ts +++ b/apps/web/src/nft/css/atoms.ts @@ -9,7 +9,9 @@ export interface Atoms extends Sprinkles { } export const atoms = ({ reset, ...rest }: Atoms) => { - if (!reset) return sprinkles(rest) + if (!reset) { + return sprinkles(rest) + } const elementReset = resetStyles.element[reset as keyof typeof resetStyles.element] diff --git a/apps/web/src/nft/hooks/useBag.ts b/apps/web/src/nft/hooks/useBag.ts index 0e35bb840b2..cf195c45e79 100644 --- a/apps/web/src/nft/hooks/useBag.ts +++ b/apps/web/src/nft/hooks/useBag.ts @@ -38,11 +38,14 @@ export const useBag = createWithEqualityFn()( })), markAssetAsReviewed: (asset, toKeep) => set(({ itemsInBag }) => { - if (itemsInBag.length === 0) return { itemsInBag: [] } + if (itemsInBag.length === 0) { + return { itemsInBag: [] } + } const itemsInBagCopy = [...itemsInBag] const index = itemsInBagCopy.findIndex((item) => item.asset.id === asset.id) - if (!toKeep && index !== -1) itemsInBagCopy.splice(index, 1) - else if (index !== -1) { + if (!toKeep && index !== -1) { + itemsInBagCopy.splice(index, 1) + } else if (index !== -1) { itemsInBagCopy[index].status = BagItemStatus.REVIEWED } return { @@ -70,7 +73,9 @@ export const useBag = createWithEqualityFn()( })), addAssetsToBag: (assets, fromSweep = false) => set(({ itemsInBag }) => { - if (get().isLocked) return { itemsInBag: get().itemsInBag } + if (get().isLocked) { + return { itemsInBag: get().itemsInBag } + } const items: BagItem[] = [] const itemsInBagCopy = [...itemsInBag] assets.forEach((asset) => { @@ -91,23 +96,28 @@ export const useBag = createWithEqualityFn()( items.push(assetWithId) } }) - if (itemsInBag.length === 0) + if (itemsInBag.length === 0) { return { itemsInBag: items, bagStatus: BagStatus.ADDING_TO_BAG, usedSweep: fromSweep, } - else + } else { return { itemsInBag: [...itemsInBagCopy, ...items], bagStatus: BagStatus.ADDING_TO_BAG, usedSweep: fromSweep, } + } }), removeAssetsFromBag: (assets, fromSweep = false) => { set(({ itemsInBag }) => { - if (get().isLocked) return { itemsInBag: get().itemsInBag } - if (itemsInBag.length === 0) return { itemsInBag: [] } + if (get().isLocked) { + return { itemsInBag: get().itemsInBag } + } + if (itemsInBag.length === 0) { + return { itemsInBag: [] } + } const itemsCopy = itemsInBag.filter( (item) => !assets.some((asset) => @@ -124,22 +134,25 @@ export const useBag = createWithEqualityFn()( }, lockSweepItems: (contractAddress) => set(({ itemsInBag }) => { - if (get().isLocked) return { itemsInBag: get().itemsInBag } + if (get().isLocked) { + return { itemsInBag: get().itemsInBag } + } const itemsInBagCopy = itemsInBag.map((item) => item.asset.address === contractAddress && item.inSweep ? { ...item, inSweep: false } : item ) - if (itemsInBag.length === 0) + if (itemsInBag.length === 0) { return { itemsInBag, } - else + } else { return { itemsInBag: [...itemsInBagCopy], } + } }), reset: () => set(() => { - if (!get().isLocked) + if (!get().isLocked) { return { bagStatus: BagStatus.ADDING_TO_BAG, itemsInBag: [], @@ -148,7 +161,9 @@ export const useBag = createWithEqualityFn()( bagManuallyClosed: false, bagExpanded: false, } - else return {} + } else { + return {} + } }), }), { name: 'useBag' } diff --git a/apps/web/src/nft/hooks/usePurchaseAssets.ts b/apps/web/src/nft/hooks/usePurchaseAssets.ts index e0f47c696a9..3044323828e 100644 --- a/apps/web/src/nft/hooks/usePurchaseAssets.ts +++ b/apps/web/src/nft/hooks/usePurchaseAssets.ts @@ -27,7 +27,9 @@ export function usePurchaseAssets(): ( return useCallback( async (routingData: RouteResponse, assetsToBuy: UpdatedGenieAsset[], purchasingWithErc20 = false) => { - if (!signer) return + if (!signer) { + return + } const purchaseResponse = await sendTransaction(signer, assetsToBuy, routingData, purchasingWithErc20) diff --git a/apps/web/src/nft/hooks/useSellAsset.ts b/apps/web/src/nft/hooks/useSellAsset.ts index feaafcb1b90..213841e37c9 100644 --- a/apps/web/src/nft/hooks/useSellAsset.ts +++ b/apps/web/src/nft/hooks/useSellAsset.ts @@ -26,16 +26,21 @@ export const useSellAsset = create()( showResolveIssues: false, selectSellAsset: (asset) => set(({ sellAssets }) => { - if (sellAssets.length === 0) return { sellAssets: [asset] } - else return { sellAssets: [...sellAssets, asset] } + if (sellAssets.length === 0) { + return { sellAssets: [asset] } + } else { + return { sellAssets: [...sellAssets, asset] } + } }), removeSellAsset: (asset) => { set(({ sellAssets }) => { - if (sellAssets.length === 0) return { sellAssets: [] } - else + if (sellAssets.length === 0) { + return { sellAssets: [] } + } else { sellAssets.find( (x) => asset.tokenId === x.tokenId && x.asset_contract.address === asset.asset_contract.address ) + } const assetsCopy = [...sellAssets] assetsCopy.splice( sellAssets.findIndex( @@ -66,9 +71,15 @@ export const useSellAsset = create()( ) if (asset.newListings && listingIndex != null && listingIndex > -1) { asset.newListings[listingIndex] = { price, marketplace, overrideFloorPrice: false } - if (listingIndex === 0) asset.marketAgnosticPrice = price - } else asset.newListings?.push({ price, marketplace, overrideFloorPrice: false }) - } else asset.marketAgnosticPrice = price + if (listingIndex === 0) { + asset.marketAgnosticPrice = price + } + } else { + asset.newListings?.push({ price, marketplace, overrideFloorPrice: false }) + } + } else { + asset.marketAgnosticPrice = price + } const index = sellAssets.findIndex( (n) => n.tokenId === asset.tokenId && n.asset_contract.address === asset.asset_contract.address ) diff --git a/apps/web/src/nft/hooks/useSendTransaction.ts b/apps/web/src/nft/hooks/useSendTransaction.ts index 98ddf99a745..35bad24a3f8 100644 --- a/apps/web/src/nft/hooks/useSendTransaction.ts +++ b/apps/web/src/nft/hooks/useSendTransaction.ts @@ -4,9 +4,9 @@ import { hexStripZeros } from '@ethersproject/bytes' import { ContractReceipt } from '@ethersproject/contracts' import type { JsonRpcSigner } from '@ethersproject/providers' import { NFTEventName } from '@uniswap/analytics-events' -import { sendAnalyticsEvent } from 'analytics' import ERC1155 from 'uniswap/src/abis/erc1155.json' import ERC721 from 'uniswap/src/abis/erc721.json' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' import { create } from 'zustand' import { devtools } from 'zustand/middleware' diff --git a/apps/web/src/nft/hooks/useSubscribeTransactionState.ts b/apps/web/src/nft/hooks/useSubscribeTransactionState.ts index 8046de1ebfe..b82f4751534 100644 --- a/apps/web/src/nft/hooks/useSubscribeTransactionState.ts +++ b/apps/web/src/nft/hooks/useSubscribeTransactionState.ts @@ -19,11 +19,15 @@ export function useSubscribeTransactionState(setModalIsOpen: (isOpen: boolean) = }, []) useEffect(() => { - if (transactionStateRef.current === TxStateType.Confirming) setBagStatus(BagStatus.PROCESSING_TRANSACTION) + if (transactionStateRef.current === TxStateType.Confirming) { + setBagStatus(BagStatus.PROCESSING_TRANSACTION) + } if (transactionStateRef.current === TxStateType.Denied || transactionStateRef.current === TxStateType.Invalid) { if (transactionStateRef.current === TxStateType.Invalid) { setBagStatus(BagStatus.WARNING) - } else setBagStatus(BagStatus.CONFIRM_REVIEW) + } else { + setBagStatus(BagStatus.CONFIRM_REVIEW) + } setTransactionState(TxStateType.New) setBagLocked(false) diff --git a/apps/web/src/nft/hooks/useWalletCollections.ts b/apps/web/src/nft/hooks/useWalletCollections.ts index 2daa7132a9c..059222f0219 100644 --- a/apps/web/src/nft/hooks/useWalletCollections.ts +++ b/apps/web/src/nft/hooks/useWalletCollections.ts @@ -38,10 +38,13 @@ export const useWalletCollections = create()( }), setCollectionFilters: (address) => set(({ collectionFilters }) => { - if (collectionFilters.length === 0) return { collectionFilters: [address] } - else if (collectionFilters.some((x) => x === address)) + if (collectionFilters.length === 0) { + return { collectionFilters: [address] } + } else if (collectionFilters.some((x) => x === address)) { return { collectionFilters: collectionFilters.filter((n) => n !== address) } - else return { collectionFilters: [...collectionFilters, address] } + } else { + return { collectionFilters: [...collectionFilters, address] } + } }), clearCollectionFilters: () => set(() => { @@ -62,13 +65,15 @@ export const useWalletCollections = create()( const filterWalletAssets = (walletAssets: WalletAsset[], listFilter: string) => { let displayAssets = walletAssets - if (listFilter === 'Listed') + if (listFilter === 'Listed') { displayAssets = displayAssets?.filter((x) => { return x.listing_date !== null }) - if (listFilter === 'Unlisted') + } + if (listFilter === 'Unlisted') { displayAssets = displayAssets?.filter((x) => { return x.listing_date === null }) + } return displayAssets } diff --git a/apps/web/src/nft/pages/asset/Asset.tsx b/apps/web/src/nft/pages/asset/Asset.tsx index 17b5f32b22c..c4d0b34ce58 100644 --- a/apps/web/src/nft/pages/asset/Asset.tsx +++ b/apps/web/src/nft/pages/asset/Asset.tsx @@ -1,5 +1,4 @@ import { InterfacePageName } from '@uniswap/analytics-events' -import { Trace } from 'analytics' import { useNftAssetDetails } from 'graphql/data/nft/Details' import { t } from 'i18n' import { AssetDetails } from 'nft/components/details/AssetDetails' @@ -12,6 +11,7 @@ import { Helmet } from 'react-helmet-async/lib/index' import { Navigate, useParams } from 'react-router-dom' import { formatNFTAssetMetatagTitleName } from 'shared-cloud/metatags' import styled from 'styled-components' +import Trace from 'uniswap/src/features/telemetry/Trace' const AssetContainer = styled.div` display: flex; @@ -63,21 +63,23 @@ const AssetPage = () => { return } - if (loading) return + if (loading) { + return + } return ( <> - {asset.name ?? ''} {asset.name ? '|' : ''} {collection.collectionName ?? t`Explore NFTs`} on Uniswap + {asset.name ?? ''} {asset.name ? '|' : ''} {collection.collectionName ?? t('nft.explore')} on Uniswap {metaTags.map((tag, index) => ( ))} {!!asset && !!collection ? ( diff --git a/apps/web/src/nft/pages/collection/index.tsx b/apps/web/src/nft/pages/collection/index.tsx index e8386d7e4a6..dd5fd3fc749 100644 --- a/apps/web/src/nft/pages/collection/index.tsx +++ b/apps/web/src/nft/pages/collection/index.tsx @@ -1,11 +1,11 @@ import { InterfacePageName } from '@uniswap/analytics-events' -import { Trace } from 'analytics' import Column from 'components/Column' import { OpacityHoverState } from 'components/Common' import Row from 'components/Row' import { LoadingBubble } from 'components/Tokens/loading' import { useCollection } from 'graphql/data/nft/Collection' import { useIsMobile, useScreenSize } from 'hooks/screenSize' +import { useAccount } from 'hooks/useAccount' import { t } from 'i18n' import { BAG_WIDTH, XXXL_BAG_WIDTH } from 'nft/components/bag/Bag' import { MobileHoverBag } from 'nft/components/bag/MobileHoverBag' @@ -26,7 +26,7 @@ import styled from 'styled-components' import { ThemedText } from 'theme/components' import { TRANSITION_DURATIONS } from 'theme/styles' import { Z_INDEX } from 'theme/zIndex' -import { useChainId } from 'wagmi' +import Trace from 'uniswap/src/features/telemetry/Trace' const FILTER_WIDTH = 332 const EMPTY_TRAIT_OBJ = {} @@ -134,7 +134,7 @@ const Collection = () => { const setMarketCount = useCollectionFilters((state) => state.setMarketCount) const isBagExpanded = useBag((state) => state.bagExpanded) const setBagExpanded = useBag((state) => state.setBagExpanded) - const chainId = useChainId() + const { chainId } = useAccount() const screenSize = useScreenSize() const { data: collectionStats, loading } = useCollection(contractAddress as string) @@ -175,7 +175,9 @@ const Collection = () => { }, [collectionStats?.marketplaceCount, setMarketCount]) useEffect(() => { - if (isBagExpanded && isFiltersExpanded && !screenSize['xl']) setFiltersExpanded(false) + if (isBagExpanded && isFiltersExpanded && !screenSize['xl']) { + setFiltersExpanded(false) + } }, [isBagExpanded, isFiltersExpanded, screenSize, setFiltersExpanded]) useEffect(() => { @@ -183,8 +185,12 @@ const Collection = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []) - if (loading) return - if (!collectionStats.name) return + if (loading) { + return + } + if (!collectionStats.name) { + return + } const toggleActivity = () => { isActivityToggled @@ -205,9 +211,9 @@ const Collection = () => { ))} { return ( <> - + diff --git a/apps/web/src/nft/pages/profile/index.tsx b/apps/web/src/nft/pages/profile/index.tsx index 819a2b55239..bb9b3d0d008 100644 --- a/apps/web/src/nft/pages/profile/index.tsx +++ b/apps/web/src/nft/pages/profile/index.tsx @@ -1,10 +1,9 @@ import { InterfacePageName } from '@uniswap/analytics-events' import { useWeb3React } from '@web3-react/core' -import { Trace } from 'analytics' import { useToggleAccountDrawer } from 'components/AccountDrawer/MiniPortfolio/hooks' import { ButtonPrimary } from 'components/Button' import useENSName from 'hooks/useENSName' -import { t, Trans } from 'i18n' +import { Trans, t } from 'i18n' import { XXXL_BAG_WIDTH } from 'nft/components/bag/Bag' import { ListPage } from 'nft/components/profile/list/ListPage' import { ProfilePage } from 'nft/components/profile/view/ProfilePage' @@ -15,8 +14,8 @@ import { Helmet } from 'react-helmet-async/lib/index' import styled from 'styled-components' import { BREAKPOINTS } from 'theme' import { ThemedText } from 'theme/components' +import Trace from 'uniswap/src/features/telemetry/Trace' import { shortenAddress } from 'utilities/src/addresses' - import { LIST_PAGE_MARGIN, LIST_PAGE_MARGIN_MOBILE } from './shared' const ProfilePageWrapper = styled.div` @@ -64,16 +63,16 @@ const ConnectWalletButton = styled(ButtonPrimary)` function getProfilePageTitle(account: string | undefined, ENSName: string | null | undefined): string { if (!account) { - return t`NFT collection on Uniswap` + return t('nft.collectionOnUni') } if (!ENSName) { - return t(`NFT collection on Uniswap - {{address}}`, { + return t(`nft.collectonOnAddress`, { address: shortenAddress(account), }) } - return t(`{{name}}'s NFT collection on Uniswap`, { + return t(`nft.authorsCollectionOnUni`, { name: ENSName, }) } @@ -105,7 +104,7 @@ export default function Profile() { {getProfilePageTitle(account, ENSName)} - + {account ? ( @@ -114,11 +113,11 @@ export default function Profile() { ) : (
- No items to display + - Connect wallet +
diff --git a/apps/web/src/nft/queries/openSea/OSCollectionsFetcher.ts b/apps/web/src/nft/queries/openSea/OSCollectionsFetcher.ts index a8eb20c7907..b77d2318c27 100644 --- a/apps/web/src/nft/queries/openSea/OSCollectionsFetcher.ts +++ b/apps/web/src/nft/queries/openSea/OSCollectionsFetcher.ts @@ -29,14 +29,18 @@ export function getOSCollectionsInfiniteQueryOptions(address: string) { const OSCollectionsFetcher = async ({ params }: any): Promise => { let hasEmptyFields = false - if (!params) return [] + if (!params) { + return [] + } for (const v of Object.values(params)) { if (v === undefined) { hasEmptyFields = true } } - if (hasEmptyFields) return [] + if (hasEmptyFields) { + return [] + } const r = await fetch(`https://api.opensea.io/api/v1/collections?${new URLSearchParams(params).toString()}`) const walletCollections = await r.json() diff --git a/apps/web/src/nft/types/common/index.ts b/apps/web/src/nft/types/common/index.ts index 9c7114d7566..0a3957b7c35 100644 --- a/apps/web/src/nft/types/common/index.ts +++ b/apps/web/src/nft/types/common/index.ts @@ -107,7 +107,9 @@ export enum Markets { } export const isPooledMarket = (market?: Markets): boolean => { - if (!market) return false + if (!market) { + return false + } return market === Markets.NFTX || market === Markets.NFT20 || market === Markets.Sudoswap } diff --git a/apps/web/src/nft/utils/buildSellObject.ts b/apps/web/src/nft/utils/buildSellObject.ts index b1f0accce24..4bc072f63b1 100644 --- a/apps/web/src/nft/utils/buildSellObject.ts +++ b/apps/web/src/nft/utils/buildSellObject.ts @@ -14,7 +14,9 @@ const buildNftTradeInput = (assets: UpdatedGenieAsset[]): NftTradeInput[] => { return assets.flatMap((asset) => { const { id, address, marketplace, priceInfo, tokenId, tokenType } = asset - if (!id || !marketplace) return [] + if (!id || !marketplace) { + return [] + } const ethAmountInput: TokenAmountInput = { amount: priceInfo.ETHPrice, diff --git a/apps/web/src/nft/utils/collection.ts b/apps/web/src/nft/utils/collection.ts index 3f5e2158799..965cd498b92 100644 --- a/apps/web/src/nft/utils/collection.ts +++ b/apps/web/src/nft/utils/collection.ts @@ -1,7 +1,9 @@ import { GenieAsset } from 'nft/types' export const isInSameSudoSwapPool = (assetA: GenieAsset, assetB: GenieAsset): boolean => { - if (!assetA.sellorders || !assetB.sellorders) return false + if (!assetA.sellorders || !assetB.sellorders) { + return false + } const assetASudoSwapPoolParameters = assetA.sellorders[0].protocolParameters const assetBSudoSwapPoolParameters = assetB.sellorders[0].protocolParameters @@ -13,8 +15,12 @@ export const isInSameSudoSwapPool = (assetA: GenieAsset, assetB: GenieAsset): bo ? (assetBSudoSwapPoolParameters.poolAddress as string) : undefined - if (!assetAPoolAddress || !assetBPoolAddress) return false - if (assetAPoolAddress !== assetBPoolAddress) return false + if (!assetAPoolAddress || !assetBPoolAddress) { + return false + } + if (assetAPoolAddress !== assetBPoolAddress) { + return false + } return true } diff --git a/apps/web/src/nft/utils/date.ts b/apps/web/src/nft/utils/date.ts index 0830ed6e7dd..d2e5f447976 100644 --- a/apps/web/src/nft/utils/date.ts +++ b/apps/web/src/nft/utils/date.ts @@ -6,8 +6,14 @@ export const getTimeDifference = (eventTimestamp: string) => { const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)) const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)) - if (days > 0) return `${days} day${days > 1 ? 's' : ''} ago` - if (hours > 0) return `${hours} hour${hours > 1 ? 's' : ''} ago` - if (minutes > 1) return `${minutes} minutes ago` + if (days > 0) { + return `${days} day${days > 1 ? 's' : ''} ago` + } + if (hours > 0) { + return `${hours} hour${hours > 1 ? 's' : ''} ago` + } + if (minutes > 1) { + return `${minutes} minutes ago` + } return 'Just now' } diff --git a/apps/web/src/nft/utils/isAudio.ts b/apps/web/src/nft/utils/isAudio.ts index d07d3eb94e0..3f945c3e86b 100644 --- a/apps/web/src/nft/utils/isAudio.ts +++ b/apps/web/src/nft/utils/isAudio.ts @@ -1,7 +1,9 @@ const set = new Set(['mp3', 'wav']) export const isAudio = (file: string) => { - if (!file) return false + if (!file) { + return false + } const fileType = file.substring(file.lastIndexOf('.') + 1) diff --git a/apps/web/src/nft/utils/listNfts.ts b/apps/web/src/nft/utils/listNfts.ts index 52fb2e10f30..872cbbc29ba 100644 --- a/apps/web/src/nft/utils/listNfts.ts +++ b/apps/web/src/nft/utils/listNfts.ts @@ -101,8 +101,11 @@ export async function approveCollection( tx.status === 1 ? setStatus(ListingStatus.APPROVED) : setStatus(ListingStatus.FAILED) } catch (error) { - if (error.code === 4001) setStatus(ListingStatus.REJECTED) - else setStatus(ListingStatus.FAILED) + if (error.code === 4001) { + setStatus(ListingStatus.REJECTED) + } else { + setStatus(ListingStatus.FAILED) + } } } @@ -124,7 +127,9 @@ export async function signListing( const signerAddress = await signer.getAddress() const listingPrice = asset.newListings?.find((listing) => listing.marketplace.name === marketplace.name)?.price - if (!listingPrice || !asset.expirationTime || !asset.asset_contract.address || !asset.tokenId) return false + if (!listingPrice || !asset.expirationTime || !asset.asset_contract.address || !asset.tokenId) { + return false + } switch (marketplace.name) { case 'OpenSea': try { @@ -159,8 +164,11 @@ export async function signListing( res ? setStatus(ListingStatus.APPROVED) : setStatus(ListingStatus.FAILED) return res } catch (error) { - if (error.code === 4001) setStatus(ListingStatus.REJECTED) - else setStatus(ListingStatus.FAILED) + if (error.code === 4001) { + setStatus(ListingStatus.REJECTED) + } else { + setStatus(ListingStatus.FAILED) + } return false } case 'LooksRare': { @@ -226,8 +234,11 @@ export async function signListing( res ? setStatus(ListingStatus.APPROVED) : setStatus(ListingStatus.FAILED) return res } catch (error) { - if (error.code === 4001) setStatus(ListingStatus.REJECTED) - else setStatus(ListingStatus.FAILED) + if (error.code === 4001) { + setStatus(ListingStatus.REJECTED) + } else { + setStatus(ListingStatus.FAILED) + } return false } } @@ -261,8 +272,11 @@ export async function signListing( resp ? setStatus(ListingStatus.APPROVED) : setStatus(ListingStatus.FAILED) return resp } catch (error) { - if (error.code === 4001) setStatus(ListingStatus.REJECTED) - else setStatus(ListingStatus.FAILED) + if (error.code === 4001) { + setStatus(ListingStatus.REJECTED) + } else { + setStatus(ListingStatus.FAILED) + } return false } } diff --git a/apps/web/src/nft/utils/numbers.ts b/apps/web/src/nft/utils/numbers.ts index 0d2d15f259e..7f35e174049 100644 --- a/apps/web/src/nft/utils/numbers.ts +++ b/apps/web/src/nft/utils/numbers.ts @@ -1,6 +1,10 @@ export const roundWholePercentage = (n: number): string => { - if (n === 0) return '0' - if (!n) return '' + if (n === 0) { + return '0' + } + if (!n) { + return '' + } if (n < 1) { return '<1' } diff --git a/apps/web/src/nft/utils/pooledAssets.ts b/apps/web/src/nft/utils/pooledAssets.ts index 77c8d315f4a..337bdd88a6d 100644 --- a/apps/web/src/nft/utils/pooledAssets.ts +++ b/apps/web/src/nft/utils/pooledAssets.ts @@ -78,13 +78,16 @@ const calcSudoSwapXykBondingCurve = ( } const calcSudoSwapPrice = (asset: GenieAsset, position = 0): string | undefined => { - if (!asset.sellorders) return undefined + if (!asset.sellorders) { + return undefined + } const sudoSwapParameters = asset.sellorders[0].protocolParameters const sudoSwapPool = getPoolParameters(sudoSwapParameters) - if (!sudoSwapPool.fee || !sudoSwapPool.delta || !sudoSwapPool.spotPrice || !sudoSwapPool.bondingCurve) + if (!sudoSwapPool.fee || !sudoSwapPool.delta || !sudoSwapPool.spotPrice || !sudoSwapPool.bondingCurve) { return undefined + } let currentPrice = BigNumber.from(sudoSwapPool.spotPrice) const delta = BigNumber.from(sudoSwapPool.delta) @@ -109,7 +112,9 @@ const calcSudoSwapPrice = (asset: GenieAsset, position = 0): string | undefined } const calcAmmBasedPoolprice = (asset: GenieAsset, position = 0): string => { - if (!asset.sellorders) return '' + if (!asset.sellorders) { + return '' + } let amountToBuy: BigNumber = BigNumber.from(0) let marginalBuy: BigNumber = BigNumber.from(0) @@ -172,8 +177,12 @@ const calcAmmBasedPoolprice = (asset: GenieAsset, position = 0): string => { } export const calcPoolPrice = (asset: GenieAsset, position = 0): string => { - if (!asset.sellorders) return '' - if (asset.marketplace === Markets.Sudoswap) return calcSudoSwapPrice(asset, position) ?? '0' + if (!asset.sellorders) { + return '' + } + if (asset.marketplace === Markets.Sudoswap) { + return calcSudoSwapPrice(asset, position) ?? '0' + } return calcAmmBasedPoolprice(asset, position) } @@ -203,12 +212,13 @@ export const recalculateBagUsingPooledAssets = (uncheckedItemsInBag: BagItem[]) uncheckedItemsInBag.every( (item) => item.status === BagItemStatus.REVIEWED || item.status === BagItemStatus.REVIEWING_PRICE_CHANGE ) - ) + ) { return uncheckedItemsInBag + } const itemsInBag = [...uncheckedItemsInBag] itemsInBag.forEach((item) => { - if (item.asset.marketplace) + if (item.asset.marketplace) { if (isPooledMarket(item.asset.marketplace)) { const asset = item.asset const isPriceChangedAsset = !!asset.updatedPriceInfo @@ -224,10 +234,13 @@ export const recalculateBagUsingPooledAssets = (uncheckedItemsInBag: BagItem[]) itemsInPool.findIndex((itemInPool) => itemInPool.asset.tokenId === asset.tokenId) ) - if (isPriceChangedAsset && item.asset.updatedPriceInfo) + if (isPriceChangedAsset && item.asset.updatedPriceInfo) { item.asset.updatedPriceInfo.ETHPrice = item.asset.updatedPriceInfo.basePrice = calculatedPrice - else item.asset.priceInfo.ETHPrice = calculatedPrice + } else { + item.asset.priceInfo.ETHPrice = calculatedPrice + } } + } }) return itemsInBag diff --git a/apps/web/src/nft/utils/transactionResponse.ts b/apps/web/src/nft/utils/transactionResponse.ts index 30da6566e8f..f601a174667 100644 --- a/apps/web/src/nft/utils/transactionResponse.ts +++ b/apps/web/src/nft/utils/transactionResponse.ts @@ -55,5 +55,7 @@ export const getSuccessfulImageSize = (numSuccessful: number, isMobile: boolean) return 136 / sizeModifier } else if (numSuccessful >= 13 && numSuccessful < 21) { return 108 / sizeModifier - } else return isMobile ? 39 : 64 + } else { + return isMobile ? 39 : 64 + } } diff --git a/apps/web/src/nft/utils/txRoute/combineItemsWithTxRoute.ts b/apps/web/src/nft/utils/txRoute/combineItemsWithTxRoute.ts index a2bac03f30e..0f029168bf6 100644 --- a/apps/web/src/nft/utils/txRoute/combineItemsWithTxRoute.ts +++ b/apps/web/src/nft/utils/txRoute/combineItemsWithTxRoute.ts @@ -36,7 +36,9 @@ const isAveragedPrice = ( route: RoutingItem, txRoute?: RoutingItem[] ): boolean => { - if (!(route && 'priceInfo' in route.assetOut)) return false + if (!(route && 'priceInfo' in route.assetOut)) { + return false + } return ( !!item.marketplace && diff --git a/apps/web/src/nft/utils/updatedAssets.ts b/apps/web/src/nft/utils/updatedAssets.ts index fdecfd5ac9f..f4e6cb90649 100644 --- a/apps/web/src/nft/utils/updatedAssets.ts +++ b/apps/web/src/nft/utils/updatedAssets.ts @@ -2,7 +2,9 @@ import { BigNumber } from '@ethersproject/bignumber' import { UpdatedGenieAsset } from 'nft/types' const updatedAssetPriceDifference = (asset: UpdatedGenieAsset) => { - if (!asset.updatedPriceInfo) return BigNumber.from(0) + if (!asset.updatedPriceInfo) { + return BigNumber.from(0) + } return BigNumber.from(asset.updatedPriceInfo.ETHPrice).sub(BigNumber.from(asset.priceInfo.ETHPrice)) } diff --git a/apps/web/src/nft/utils/urlParams.ts b/apps/web/src/nft/utils/urlParams.ts index bbfbed32e36..a37ee3ad292 100644 --- a/apps/web/src/nft/utils/urlParams.ts +++ b/apps/web/src/nft/utils/urlParams.ts @@ -87,8 +87,9 @@ const urlParamsUtils = { !trait_type.endsWith(')') && trait_value.endsWith(')') && !trait_value.startsWith('(') - ) + ) { clonedQuery['traits'] = [`${trait_type},${trait_value}`] + } } } @@ -160,7 +161,9 @@ export const syncLocalFiltersWithURL = (state: CollectionFilters) => { } export const applyFiltersFromURL = (location: Location, collectionStats: GenieCollection) => { - if (!location.search) return + if (!location.search) { + return + } const query = qs.parse(location.search, { arrayFormat: 'comma', diff --git a/apps/web/src/pages/AddLiquidity/blastAlerts.tsx b/apps/web/src/pages/AddLiquidity/blastAlerts.tsx index 481e35d0abf..fee34319a52 100644 --- a/apps/web/src/pages/AddLiquidity/blastAlerts.tsx +++ b/apps/web/src/pages/AddLiquidity/blastAlerts.tsx @@ -54,15 +54,10 @@ export function BlastRebasingModal({ currencyIdA, currencyIdB, onContinue }: Bla icon={} title={ - Rebasing is unavailable on v3 + } - description={ - - On Blast, USDB and WETH are rebasing tokens that automatically earn yield. Due to incompatibility with Uniswap - v3, LP positions with USDB or WETH won't earn rebasing yield, but will in Uniswap v2. - - } + description={} body={ @@ -73,11 +68,11 @@ export function BlastRebasingModal({ currencyIdA, currencyIdB, onContinue }: Bla onCancel={onContinue} buttonsConfig={{ left: { - title: Continue on v3, + title: , onClick: onContinue, }, right: { - title: Switch to v2, + title: , onClick: () => navigate(`/add/v2/${currencyIdA ?? 'ETH'}/${currencyIdB ?? ''}`), type: DialogButtonType.Accent, }, @@ -126,16 +121,13 @@ export function BlastRebasingAlert() { - Rebasing unavailable on v3 + - - On Blast, USDB and WETH are rebasing tokens that automatically earn yield. Due to incompatibility with - Uniswap v3, LP positions with USDB or WETH won't earn rebasing yield, but will in Uniswap v2. - {' '} + {' '} - Learn more + diff --git a/apps/web/src/pages/AddLiquidity/index.tsx b/apps/web/src/pages/AddLiquidity/index.tsx index 43a0d70dee1..cf64c220857 100644 --- a/apps/web/src/pages/AddLiquidity/index.tsx +++ b/apps/web/src/pages/AddLiquidity/index.tsx @@ -1,16 +1,22 @@ import { BigNumber } from '@ethersproject/bignumber' import type { TransactionResponse } from '@ethersproject/providers' -import { BrowserEvent, InterfaceElementName, InterfaceEventName, LiquidityEventName } from '@uniswap/analytics-events' +import { InterfaceElementName, InterfaceEventName, LiquidityEventName } from '@uniswap/analytics-events' import { ChainId, Currency, CurrencyAmount, NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, Percent } from '@uniswap/sdk-core' import { FeeAmount, NonfungiblePositionManager } from '@uniswap/v3-sdk' -import { TraceEvent, sendAnalyticsEvent, useTrace } from 'analytics' import { useToggleAccountDrawer } from 'components/AccountDrawer/MiniPortfolio/hooks' +import { OutOfSyncWarning } from 'components/addLiquidity/OutOfSyncWarning' import OwnershipWarning from 'components/addLiquidity/OwnershipWarning' +import { TokenTaxV3Warning } from 'components/addLiquidity/TokenTaxV3Warning' import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter' import { CHAIN_INFO, isSupportedChainId, useIsSupportedChainId } from 'constants/chains' +import { useAccount } from 'hooks/useAccount' +import { useEthersSigner } from 'hooks/useEthersSigner' +import { useIsPoolOutOfSync } from 'hooks/useIsPoolOutOfSync' import usePrevious from 'hooks/usePrevious' import { Trans, t } from 'i18n' +import { atomWithStorage, useAtomValue, useUpdateAtom } from 'jotai/utils' import { useSingleCallResult } from 'lib/hooks/multicall' +import { BlastRebasingAlert, BlastRebasingModal } from 'pages/AddLiquidity/blastAlerts' import { BodyWrapper } from 'pages/AppBody' import { PositionPageUnsupportedContent } from 'pages/Pool/PositionPage' import { useCallback, useEffect, useMemo, useState } from 'react' @@ -26,17 +32,12 @@ import { import styled, { useTheme } from 'styled-components' import { ThemedText } from 'theme/components' import { Text } from 'ui/src' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { addressesAreEquivalent } from 'utils/addressesAreEquivalent' import { WrongChainError } from 'utils/errors' import { NumberType, useFormatter } from 'utils/formatNumbers' - -import { OutOfSyncWarning } from 'components/addLiquidity/OutOfSyncWarning' -import { TokenTaxV3Warning } from 'components/addLiquidity/TokenTaxV3Warning' -import { useEthersSigner } from 'hooks/useEthersSigner' -import { useIsPoolOutOfSync } from 'hooks/useIsPoolOutOfSync' -import { atomWithStorage, useAtomValue, useUpdateAtom } from 'jotai/utils' -import { BlastRebasingAlert, BlastRebasingModal } from 'pages/AddLiquidity/blastAlerts' -import { useAccount } from 'wagmi' import { ButtonError, ButtonLight, ButtonPrimary, ButtonText } from '../../components/Button' import { BlueCard, OutlineCard, YellowCard } from '../../components/Card' import { AutoColumn } from '../../components/Column' @@ -90,8 +91,8 @@ const BLAST_REBASING_TOKENS = [ ] export default function AddLiquidityWrapper() { - const account = useAccount() - const isSupportedChain = useIsSupportedChainId(account.chainId) + const { chainId } = useAccount() + const isSupportedChain = useIsSupportedChainId(chainId) if (isSupportedChain) { return } else { @@ -229,11 +230,15 @@ function AddLiquidity() { // check whether the user has approved the router on the tokens const [approvalA, approveACallback] = useApproveCallback( argentWalletContract ? undefined : parsedAmounts[Field.CURRENCY_A], - account.status === 'connected' ? NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[account.chainId] : undefined + account.status === 'connected' && account.chainId + ? NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[account.chainId] + : undefined ) const [approvalB, approveBCallback] = useApproveCallback( argentWalletContract ? undefined : parsedAmounts[Field.CURRENCY_B], - account.status === 'connected' ? NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[account.chainId] : undefined + account.status === 'connected' && account.chainId + ? NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[account.chainId] + : undefined ) const allowedSlippage = useUserSlippageToleranceWithDefault( @@ -241,7 +246,9 @@ function AddLiquidity() { ) async function onAdd() { - if (account.status !== 'connected' || !signer) return + if (account.status !== 'connected' || !signer || !account.chainId) { + return + } if (!positionManager || !baseCurrency || !quoteCurrency) { return @@ -298,7 +305,9 @@ function AddLiquidity() { } const connectedChainId = await signer.getChainId() - if (account.chainId !== connectedChainId) throw new WrongChainError() + if (account.chainId !== connectedChainId) { + throw new WrongChainError() + } setAttemptingTxn(true) @@ -354,11 +363,15 @@ function AddLiquidity() { // prevent weth + eth const isETHOrWETHNew = currencyIdNew === 'ETH' || - (account.status === 'connected' && currencyIdNew === WRAPPED_NATIVE_CURRENCY[account.chainId]?.address) + (account.status === 'connected' && + account.chainId && + currencyIdNew === WRAPPED_NATIVE_CURRENCY[account.chainId]?.address) const isETHOrWETHOther = currencyIdOther !== undefined && (currencyIdOther === 'ETH' || - (account.status === 'connected' && currencyIdOther === WRAPPED_NATIVE_CURRENCY[account.chainId]?.address)) + (account.status === 'connected' && + account.chainId && + currencyIdOther === WRAPPED_NATIVE_CURRENCY[account.chainId]?.address)) if (isETHOrWETHNew && isETHOrWETHOther) { return [currencyIdNew, undefined] @@ -449,9 +462,13 @@ function AddLiquidity() { getSetFullRange() const minPrice = pricesAtLimit[Bound.LOWER] - if (minPrice) searchParams.set('minPrice', minPrice.toSignificant(5)) + if (minPrice) { + searchParams.set('minPrice', minPrice.toSignificant(5)) + } const maxPrice = pricesAtLimit[Bound.UPPER] - if (maxPrice) searchParams.set('maxPrice', maxPrice.toSignificant(5)) + if (maxPrice) { + searchParams.set('maxPrice', maxPrice.toSignificant(5)) + } setSearchParams(searchParams) }, [getSetFullRange, pricesAtLimit, searchParams, setSearchParams]) @@ -493,21 +510,21 @@ function AddLiquidity() { const Buttons = () => addIsUnsupported ? ( - - Unsupported Asset + + ) : account.status !== 'connected' ? ( - - Connect wallet + - +
) : ( {(approvalA === ApprovalState.NOT_APPROVED || @@ -524,10 +541,16 @@ function AddLiquidity() { > {approvalA === ApprovalState.PENDING ? ( - Approving {{ amount: currencies[Field.CURRENCY_A]?.symbol }} + ) : ( - Approve {{ amount: currencies[Field.CURRENCY_A]?.symbol }} + )} )} @@ -539,10 +562,16 @@ function AddLiquidity() { > {approvalB === ApprovalState.PENDING ? ( - Approving {{ amount: currencies[Field.CURRENCY_B]?.symbol }} + ) : ( - Approve {{ amount: currencies[Field.CURRENCY_B]?.symbol }} + )} )} @@ -559,7 +588,7 @@ function AddLiquidity() { } error={!isValid && !!parsedAmounts[Field.CURRENCY_A] && !!parsedAmounts[Field.CURRENCY_B]} > - {errorMessage ? errorMessage : Preview} + {errorMessage ? errorMessage : } ) @@ -603,8 +632,11 @@ function AddLiquidity() { <> - {t(`Add liquidity to {{token pair}} ({{chain}}) on Uniswap`, { - tokenPair: `${quoteCurrency?.symbol}/${baseCurrency?.symbol}`, + {t('pool.addLiquidity.seoTitle', { + tokenPair: + quoteCurrency?.symbol && baseCurrency?.symbol + ? `${quoteCurrency.symbol}/${baseCurrency.symbol}` + : quoteCurrency?.symbol ?? baseCurrency?.symbol ?? 'pools', chain: CHAIN_INFO[isSupportedChainId(account.chainId) ? account.chainId : ChainId.MAINNET].label, })} @@ -617,7 +649,7 @@ function AddLiquidity() { hash={txHash} reviewContent={() => ( Add Liquidity
} + title={} onDismiss={handleDismissConfirmation} topContent={() => ( ( - Add + )} @@ -645,6 +677,7 @@ function AddLiquidity() { @@ -653,7 +686,7 @@ function AddLiquidity() { - Clear all + @@ -678,7 +711,7 @@ function AddLiquidity() { )} - Select pair + @@ -722,7 +755,7 @@ function AddLiquidity() { {hasExistingPosition && existingPosition && ( Selected range} + title={} inRange={!outOfRange} ticksAtLimit={ticksAtLimit} showBlastAlert={showBlastRebasingWarning} @@ -735,7 +768,7 @@ function AddLiquidity() { - Set price range + {Boolean(baseCurrency && quoteCurrency) && ( @@ -785,10 +818,7 @@ function AddLiquidity() { - - Your position will not earn fees or be used in trades until the market price moves into - your range. - + @@ -799,7 +829,7 @@ function AddLiquidity() { - Invalid range selected. The min price must be lower than the max price. + @@ -812,14 +842,14 @@ function AddLiquidity() { {Boolean(price && baseCurrency && quoteCurrency && !noLiquidity) && ( - Current price: + {price && } {baseCurrency && ( - {quoteCurrency?.symbol} per {baseCurrency.symbol} + {quoteCurrency?.symbol} {baseCurrency.symbol} )} @@ -856,11 +886,7 @@ function AddLiquidity() { textAlign="left" color={theme.accent1} > - - This pool must be initialized before you can add liquidity. To initialize, select a - starting price for the pool. Then, enter your liquidity price range and deposit amount. - Gas fees will be higher than usual due to the initialization transaction. - + )} @@ -879,7 +905,7 @@ function AddLiquidity() { }} > - Starting {{ sym: baseCurrency?.symbol }} Price: + {price ? ( @@ -890,7 +916,10 @@ function AddLiquidity() { text={invertPrice ? price?.invert()?.toSignificant(8) : price?.toSignificant(8)} />{' '} - {quoteCurrency?.symbol} per {baseCurrency?.symbol} + @@ -908,7 +937,11 @@ function AddLiquidity() { - {hasExistingPosition ? Add more liquidity : Deposit amounts} + {hasExistingPosition ? ( + + ) : ( + + )} () - const chainId = useChainId() + const { chainId } = useAccount() // prevent weth + eth const isETHOrWETHA = diff --git a/apps/web/src/pages/AddLiquidityV2/ConfirmAddModalBottom.tsx b/apps/web/src/pages/AddLiquidityV2/ConfirmAddModalBottom.tsx index 91f5ce4663c..02b363d156d 100644 --- a/apps/web/src/pages/AddLiquidityV2/ConfirmAddModalBottom.tsx +++ b/apps/web/src/pages/AddLiquidityV2/ConfirmAddModalBottom.tsx @@ -29,7 +29,7 @@ export function ConfirmAddModalBottom({ <> - {{ depositedAmtA }} Deposited + @@ -38,7 +38,7 @@ export function ConfirmAddModalBottom({ - {{ depositedAmtB }} Deposited + @@ -47,7 +47,7 @@ export function ConfirmAddModalBottom({ - Rates + {`1 ${currencies[Field.CURRENCY_A]?.symbol} = ${price?.toSignificant(4)} ${ @@ -64,15 +64,18 @@ export function ConfirmAddModalBottom({ - Share of Pool: + - {{ pct: noLiquidity ? '100' : poolTokenPercentage?.toSignificant(4) }}% + - {noLiquidity ? Create pool & supply : Confirm supply} + {noLiquidity ? : } diff --git a/apps/web/src/pages/AddLiquidityV2/PoolPriceBar.tsx b/apps/web/src/pages/AddLiquidityV2/PoolPriceBar.tsx index f86b3051eb9..91e01f0c925 100644 --- a/apps/web/src/pages/AddLiquidityV2/PoolPriceBar.tsx +++ b/apps/web/src/pages/AddLiquidityV2/PoolPriceBar.tsx @@ -37,17 +37,19 @@ export function PoolPriceBar({ {price?.toSignificant(6) ?? '-'} - - {{ symB: currencies[Field.CURRENCY_B]?.symbol }} per {{ symA: currencies[Field.CURRENCY_A]?.symbol }} - + {invertedPrice ?? '-'} - - {{ symA: currencies[Field.CURRENCY_A]?.symbol }} per {{ symB: currencies[Field.CURRENCY_B]?.symbol }} - + @@ -58,7 +60,7 @@ export function PoolPriceBar({ % - Share of pool + diff --git a/apps/web/src/pages/AddLiquidityV2/index.tsx b/apps/web/src/pages/AddLiquidityV2/index.tsx index 7b6b21b3b7d..1272b675f3b 100644 --- a/apps/web/src/pages/AddLiquidityV2/index.tsx +++ b/apps/web/src/pages/AddLiquidityV2/index.tsx @@ -1,12 +1,14 @@ import { BigNumber } from '@ethersproject/bignumber' import type { TransactionResponse } from '@ethersproject/providers' -import { BrowserEvent, InterfaceElementName, InterfaceEventName, LiquidityEventName } from '@uniswap/analytics-events' +import { InterfaceElementName, InterfaceEventName, LiquidityEventName } from '@uniswap/analytics-events' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' -import { TraceEvent, sendAnalyticsEvent, useTrace } from 'analytics' import { useToggleAccountDrawer } from 'components/AccountDrawer/MiniPortfolio/hooks' +import { DoubleCurrencyLogo } from 'components/DoubleLogo' import { SwitchLocaleLink } from 'components/SwitchLocaleLink' import { V2Unsupported } from 'components/V2Unsupported' import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter' +import { useAccount } from 'hooks/useAccount' +import { useEthersSigner } from 'hooks/useEthersSigner' import { useNetworkSupportsV2 } from 'hooks/useNetworkSupportsV2' import { Trans } from 'i18n' import { useCallback, useState } from 'react' @@ -14,11 +16,10 @@ import { Plus } from 'react-feather' import { useLocation, useNavigate, useParams } from 'react-router-dom' import styled, { useTheme } from 'styled-components' import { ThemedText } from 'theme/components' - -import { DoubleCurrencyLogo } from 'components/DoubleLogo' -import { useEthersSigner } from 'hooks/useEthersSigner' import { Text } from 'ui/src' -import { useAccount } from 'wagmi' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import { useTrace } from 'utilities/src/telemetry/trace/TraceContext' import { ButtonError, ButtonLight, ButtonPrimary } from '../../components/Button' import { BlueCard, LightCard } from '../../components/Card' import { AutoColumn, ColumnCenter } from '../../components/Column' @@ -68,7 +69,8 @@ export default function AddLiquidity() { const currencyA = useCurrency(currencyIdA) const currencyB = useCurrency(currencyIdB) - const wrappedNativeCurrency = account.status === 'connected' ? WRAPPED_NATIVE_CURRENCY[account.chainId] : undefined + const wrappedNativeCurrency = + account.status === 'connected' && account.chainId ? WRAPPED_NATIVE_CURRENCY[account.chainId] : undefined const oneCurrencyIsWETH = Boolean( account.chainId && @@ -144,7 +146,9 @@ export default function AddLiquidity() { const networkSupportsV2 = useNetworkSupportsV2() async function onAdd() { - if (account.status !== 'connected' || !signer || !router || !networkSupportsV2) return + if (account.status !== 'connected' || !signer || !router || !networkSupportsV2) { + return + } const { [Field.CURRENCY_A]: parsedAmountA, [Field.CURRENCY_B]: parsedAmountB } = parsedAmounts const deadline = await getDeadline() @@ -254,10 +258,7 @@ export default function AddLiquidity() {
- - Output is estimated. If the price changes by more than {{ allowed: allowedSlippage.toSignificant(4) }}% - your transaction will revert. - + )} @@ -279,11 +280,15 @@ export default function AddLiquidity() { } const pendingText = ( - - Supplying {{ amtA: parsedAmounts[Field.CURRENCY_A]?.toSignificant(6) }}{' '} - {{ symA: currencies[Field.CURRENCY_A]?.symbol }} and {{ amtB: parsedAmounts[Field.CURRENCY_B]?.toSignificant(6) }}{' '} - {{ symB: currencies[Field.CURRENCY_B]?.symbol }} - + ) const handleCurrencyASelect = useCallback( @@ -327,7 +332,9 @@ export default function AddLiquidity() { const addIsUnsupported = useIsSwapUnsupported(currencies?.CURRENCY_A, currencies?.CURRENCY_B) - if (!networkSupportsV2) return + if (!networkSupportsV2) { + return + } return ( <> @@ -341,7 +348,7 @@ export default function AddLiquidity() { hash={txHash} reviewContent={() => ( You are creating a pool : You will receive} + title={noLiquidity ? : } onDismiss={handleDismissConfirmation} topContent={modalHeader} bottomContent={modalBottom} @@ -357,13 +364,13 @@ export default function AddLiquidity() { - You are the first liquidity provider. + - The ratio of tokens you add will set the price of this pool. + - Once you are happy with the rate click supply to review. + @@ -374,13 +381,9 @@ export default function AddLiquidity() { - Tip: + {' '} - - When you add liquidity, you will receive pool tokens representing your position. These tokens - automatically earn fees proportional to your share of the pool, and can be redeemed at any - time. - + @@ -416,11 +419,7 @@ export default function AddLiquidity() { - {noLiquidity ? ( - Initial prices and pool share - ) : ( - Prices and pool share - )} + {noLiquidity ? : } {' '} @@ -438,20 +437,20 @@ export default function AddLiquidity() { {addIsUnsupported ? ( - Unsupported asset + ) : account.status !== 'connected' ? ( - - Connect wallet + - +
) : ( {(approvalA === ApprovalState.NOT_APPROVED || @@ -468,10 +467,16 @@ export default function AddLiquidity() { > {approvalA === ApprovalState.PENDING ? ( - Approving {{ sym: currencies[Field.CURRENCY_A]?.symbol }} + ) : ( - Approve {{ sym: currencies[Field.CURRENCY_A]?.symbol }} + )} )} @@ -483,10 +488,16 @@ export default function AddLiquidity() { > {approvalB === ApprovalState.PENDING ? ( - Approving {{ sym: currencies[Field.CURRENCY_B]?.symbol }} + ) : ( - Approve {{ sym: currencies[Field.CURRENCY_B]?.symbol }} + )} )} @@ -500,7 +511,7 @@ export default function AddLiquidity() { error={!isValid && !!parsedAmounts[Field.CURRENCY_A] && !!parsedAmounts[Field.CURRENCY_B]} > - {error ?? Supply} + {error ?? } diff --git a/apps/web/src/pages/App.tsx b/apps/web/src/pages/App.tsx index 00df884927d..f3cb46d2289 100644 --- a/apps/web/src/pages/App.tsx +++ b/apps/web/src/pages/App.tsx @@ -1,8 +1,8 @@ import { CustomUserProperties, getBrowser, SharedEventName } from '@uniswap/analytics-events' -import { sendAnalyticsEvent, sendInitializationEvent, Trace, user } from 'analytics' import ErrorBoundary from 'components/ErrorBoundary' import Loader from 'components/Icons/LoadingSpinner' import NavBar, { PageTabs } from 'components/NavBar' +import { MobileAppPromoBanner, useMobileAppPromoBannerEligible } from 'components/NavBar/MobileAppPromoBanner' import { UK_BANNER_HEIGHT, UK_BANNER_HEIGHT_MD, UK_BANNER_HEIGHT_SM, UkBanner } from 'components/NavBar/UkBanner' import { useFeatureFlagURLOverrides } from 'featureFlags' import { useAtom } from 'jotai' @@ -18,8 +18,11 @@ import { useRouterPreference } from 'state/user/hooks' import styled from 'styled-components' import DarkModeQueryParamReader from 'theme/components/DarkModeQueryParamReader' import { useIsDarkMode } from 'theme/components/ThemeToggle' -import { flexRowNoWrap } from 'theme/styles' +import { flexColumnNoWrap } from 'theme/styles' import { Z_INDEX } from 'theme/zIndex' +import { sendAnalyticsEvent } from 'uniswap/src/features/telemetry/send' +import Trace from 'uniswap/src/features/telemetry/Trace' +import { setUserProperty } from 'uniswap/src/features/telemetry/user' import { isPathBlocked } from 'utils/blockedPaths' import { MICROSITE_LINK } from 'utils/openDownloadApp' import { getCurrentPageFromLocation } from 'utils/urlRoutes' @@ -30,22 +33,24 @@ import { findRouteByPath, RouteDefinition, routes, useRouterConfig } from './Rou // Annotating it with webpackPreload allows it to be ready when requested. const AppChrome = lazy(() => import(/* webpackPreload: true */ './AppChrome')) -const BodyWrapper = styled.div<{ bannerIsVisible?: boolean }>` +const BodyWrapper = styled.div<{ ukBannerVisible?: boolean; mobileAppPromoBannerVisible?: boolean }>` display: flex; flex-direction: column; position: relative; width: 100%; - min-height: calc(100vh - ${({ bannerIsVisible }) => (bannerIsVisible ? UK_BANNER_HEIGHT : 0)}px); - padding: ${({ theme }) => theme.navHeight}px 0px 5rem 0px; + min-height: calc(100vh - ${({ ukBannerVisible }) => (ukBannerVisible ? UK_BANNER_HEIGHT : 0)}px); + padding: ${({ theme, mobileAppPromoBannerVisible }) => + theme.navHeight + (mobileAppPromoBannerVisible ? theme.promoBannerHeight : 0)}px + 0px 5rem 0px; align-items: center; flex: 1; @media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) { - min-height: calc(100vh - ${({ bannerIsVisible }) => (bannerIsVisible ? UK_BANNER_HEIGHT_MD : 0)}px); + min-height: calc(100vh - ${({ ukBannerVisible }) => (ukBannerVisible ? UK_BANNER_HEIGHT_MD : 0)}px); } @media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) { - min-height: calc(100vh - ${({ bannerIsVisible }) => (bannerIsVisible ? UK_BANNER_HEIGHT_SM : 0)}px); + min-height: calc(100vh - ${({ ukBannerVisible }) => (ukBannerVisible ? UK_BANNER_HEIGHT_SM : 0)}px); } ` @@ -70,22 +75,22 @@ const MobileBottomBar = styled.div` } ` -const HeaderWrapper = styled.div<{ transparent?: boolean; bannerIsVisible?: boolean; scrollY: number }>` - ${flexRowNoWrap}; +const HeaderWrapper = styled.div<{ transparent?: boolean; ukBannerVisible?: boolean; scrollY: number }>` + ${flexColumnNoWrap} background-color: ${({ theme, transparent }) => !transparent && theme.surface1}; border-bottom: ${({ theme, transparent }) => !transparent && `1px solid ${theme.surface3}`}; width: 100%; justify-content: space-between; position: fixed; - top: ${({ bannerIsVisible }) => (bannerIsVisible ? Math.max(UK_BANNER_HEIGHT - scrollY, 0) : 0)}px; + top: ${({ ukBannerVisible }) => (ukBannerVisible ? Math.max(UK_BANNER_HEIGHT - scrollY, 0) : 0)}px; z-index: ${Z_INDEX.sticky}; @media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) { - top: ${({ bannerIsVisible }) => (bannerIsVisible ? Math.max(UK_BANNER_HEIGHT_MD - scrollY, 0) : 0)}px; + top: ${({ ukBannerVisible }) => (ukBannerVisible ? Math.max(UK_BANNER_HEIGHT_MD - scrollY, 0) : 0)}px; } @media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) { - top: ${({ bannerIsVisible }) => (bannerIsVisible ? Math.max(UK_BANNER_HEIGHT_SM - scrollY, 0) : 0)}px; + top: ${({ ukBannerVisible }) => (ukBannerVisible ? Math.max(UK_BANNER_HEIGHT_SM - scrollY, 0) : 0)}px; } ` @@ -166,9 +171,10 @@ export default function App() { const Body = memo(function Body() { const routerConfig = useRouterConfig() const renderUkBanner = useRenderUkBanner() + const mobileAppPromoBannerEligible = useMobileAppPromoBannerEligible() return ( - + @@ -229,7 +235,8 @@ const Header = memo(function Header() { }, []) return ( - + + ) @@ -244,11 +251,11 @@ function UserPropertyUpdater() { useEffect(() => { // User properties *must* be set before sending corresponding event properties, // so that the event contains the correct and up-to-date user properties. - user.set(CustomUserProperties.USER_AGENT, navigator.userAgent) - user.set(CustomUserProperties.BROWSER, getBrowser()) - user.set(CustomUserProperties.SCREEN_RESOLUTION_HEIGHT, window.screen.height) - user.set(CustomUserProperties.SCREEN_RESOLUTION_WIDTH, window.screen.width) - user.set(CustomUserProperties.GIT_COMMIT_HASH, process.env.REACT_APP_GIT_COMMIT_HASH ?? 'unknown') + setUserProperty(CustomUserProperties.USER_AGENT, navigator.userAgent) + setUserProperty(CustomUserProperties.BROWSER, getBrowser()) + setUserProperty(CustomUserProperties.SCREEN_RESOLUTION_HEIGHT, window.screen.height) + setUserProperty(CustomUserProperties.SCREEN_RESOLUTION_WIDTH, window.screen.width) + setUserProperty(CustomUserProperties.GIT_COMMIT_HASH, process.env.REACT_APP_GIT_COMMIT_HASH ?? 'unknown') // Service Worker analytics const isServiceWorkerInstalled = Boolean(window.navigator.serviceWorker?.controller) @@ -269,7 +276,7 @@ function UserPropertyUpdater() { } const pageLoadProperties = { service_worker: serviceWorkerProperty, cache } - sendInitializationEvent(SharedEventName.APP_LOADED, pageLoadProperties) + sendAnalyticsEvent(SharedEventName.APP_LOADED, pageLoadProperties) const sendWebVital = (metric: string) => ({ delta }: Metric) => @@ -281,12 +288,14 @@ function UserPropertyUpdater() { }, []) useEffect(() => { - user.set(CustomUserProperties.DARK_MODE, isDarkMode) + setUserProperty(CustomUserProperties.DARK_MODE, isDarkMode) }, [isDarkMode]) useEffect(() => { - if (!rehydrated) return - user.set(CustomUserProperties.ROUTER_PREFERENCE, routerPreference) + if (!rehydrated) { + return + } + setUserProperty(CustomUserProperties.ROUTER_PREFERENCE, routerPreference) }, [routerPreference, rehydrated]) return null } diff --git a/apps/web/src/pages/CreateProposal/ProposalActionDetail.tsx b/apps/web/src/pages/CreateProposal/ProposalActionDetail.tsx index 2e13ab2b8d5..3bef25de47f 100644 --- a/apps/web/src/pages/CreateProposal/ProposalActionDetail.tsx +++ b/apps/web/src/pages/CreateProposal/ProposalActionDetail.tsx @@ -53,7 +53,7 @@ export const ProposalActionDetail = ({ [ProposalAction.TRANSFER_TOKEN]: [ { type: ProposalActionDetailField.ADDRESS, - label: To, + label: , }, { type: ProposalActionDetailField.CURRENCY, @@ -62,7 +62,7 @@ export const ProposalActionDetail = ({ [ProposalAction.APPROVE_TOKEN]: [ { type: ProposalActionDetailField.ADDRESS, - label: To, + label: , }, { type: ProposalActionDetailField.CURRENCY, diff --git a/apps/web/src/pages/CreateProposal/ProposalActionSelector.tsx b/apps/web/src/pages/CreateProposal/ProposalActionSelector.tsx index 01653a73cb2..f870ae25e43 100644 --- a/apps/web/src/pages/CreateProposal/ProposalActionSelector.tsx +++ b/apps/web/src/pages/CreateProposal/ProposalActionSelector.tsx @@ -77,7 +77,7 @@ export const ProposalActionSelector = ({ - Proposed action + {proposalAction} @@ -104,7 +104,7 @@ export function ProposalActionSelectorModal({ - Select an action + @@ -113,14 +113,14 @@ export function ProposalActionSelectorModal({ handleProposalActionSelect(ProposalAction.TRANSFER_TOKEN)}> - Transfer token + handleProposalActionSelect(ProposalAction.APPROVE_TOKEN)}> - Approve token + diff --git a/apps/web/src/pages/CreateProposal/ProposalEditor.tsx b/apps/web/src/pages/CreateProposal/ProposalEditor.tsx index 2cdebfc2fdc..eb125a446be 100644 --- a/apps/web/src/pages/CreateProposal/ProposalEditor.tsx +++ b/apps/web/src/pages/CreateProposal/ProposalEditor.tsx @@ -54,9 +54,9 @@ Insert your conclusion here return ( - Proposal + - +
diff --git a/apps/web/src/pages/CreateProposal/ProposalSubmissionModal.tsx b/apps/web/src/pages/CreateProposal/ProposalSubmissionModal.tsx index 68a05adba94..627d8fab48c 100644 --- a/apps/web/src/pages/CreateProposal/ProposalSubmissionModal.tsx +++ b/apps/web/src/pages/CreateProposal/ProposalSubmissionModal.tsx @@ -26,7 +26,7 @@ export const ProposalSubmissionModal = ({ - Submitting proposal + @@ -34,18 +34,18 @@ export const ProposalSubmissionModal = ({ - Proposal submitted + {hash && ( - View on Etherscan + )} - Return + diff --git a/apps/web/src/pages/CreateProposal/index.tsx b/apps/web/src/pages/CreateProposal/index.tsx index f50ec286b19..d3790be17c5 100644 --- a/apps/web/src/pages/CreateProposal/index.tsx +++ b/apps/web/src/pages/CreateProposal/index.tsx @@ -3,7 +3,6 @@ import { getAddress, isAddress } from '@ethersproject/address' import { InterfacePageName } from '@uniswap/analytics-events' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' -import { Trace } from 'analytics' import { ButtonError } from 'components/Button' import { BlueCard } from 'components/Card' import { AutoColumn } from 'components/Column' @@ -25,7 +24,7 @@ import { } from 'state/governance/hooks' import styled from 'styled-components' import { ExternalLink, ThemedText } from 'theme/components' - +import Trace from 'uniswap/src/features/telemetry/Trace' import { LATEST_GOVERNOR_INDEX } from '../../constants/governance' import { UNI } from '../../constants/tokens' import AppBody from '../AppBody' @@ -91,17 +90,22 @@ const CreateProposalButton = ({ onClick={handleCreateProposal} > {hasActiveOrPendingProposal ? ( - You already have an active or pending proposal + ) : !hasEnoughVote ? ( <> {formattedProposalThreshold ? ( - You must have {{ formattedProposalThreshold }} votes to submit a proposal + ) : ( - You don't have enough votes to submit a proposal + )} ) : ( - Create proposal + )} ) @@ -214,10 +218,14 @@ export default function CreateProposal() { const createProposalData: CreateProposalData = {} as CreateProposalData - if (!createProposalCallback || !proposalAction || !currencyValue.isToken) return + if (!createProposalCallback || !proposalAction || !currencyValue.isToken) { + return + } const tokenAmount = tryParseCurrencyAmount(amountValue, currencyValue) - if (!tokenAmount) return + if (!tokenAmount) { + return + } createProposalData.targets = [currencyValue.address] createProposalData.values = ['0'] @@ -253,30 +261,32 @@ ${bodyValue} setAttempting(false) }) - if (hash) setHash(hash) + if (hash) { + setHash(hash) + } } return ( - + - - Tip: Select an action and describe your proposal for the community. The proposal - cannot be modified after submission, so please verify all information before submitting. The voting - period will begin immediately and last for 7 days. To propose a custom action,{' '} - - read the docs - - . - + + + + diff --git a/apps/web/src/pages/Explore/charts/ExploreChartsSection.tsx b/apps/web/src/pages/Explore/charts/ExploreChartsSection.tsx index 3e8683e46d6..1b1627697a2 100644 --- a/apps/web/src/pages/Explore/charts/ExploreChartsSection.tsx +++ b/apps/web/src/pages/Explore/charts/ExploreChartsSection.tsx @@ -114,9 +114,9 @@ function VolumeChartSection({ chainId }: { chainId: SupportedInterfaceChainId }) if (isSmallScreen) { return ( Uniswap volume} + title={} value={cumulativeVolume} - time={Past month} + time={} /> ) } @@ -125,7 +125,7 @@ function VolumeChartSection({ chainId }: { chainId: SupportedInterfaceChainId }) - Uniswap volume +
{(() => { if (dataQuality === DataQuality.INVALID) { - const errorText = loading ? undefined : ( - Unable to display historical volume data for the current chain. - ) + const errorText = loading ? undefined : return ( ) @@ -177,19 +175,17 @@ function TVLChartSection({ chainId }: { chainId: SupportedInterfaceChainId }) { const isSmallScreen = !useScreenSize()['sm'] if (isSmallScreen) { const currentTVL = lastEntry?.values.reduce((acc, curr) => acc + curr, 0) - return Uniswap TVL} value={currentTVL} /> + return } value={currentTVL} /> } return ( - Uniswap TVL + {(() => { if (dataQuality === DataQuality.INVALID) { - const errorText = loading ? undefined : ( - Unable to display historical TVL data for the current chain. - ) + const errorText = loading ? undefined : return } diff --git a/apps/web/src/pages/Explore/index.tsx b/apps/web/src/pages/Explore/index.tsx index 92211e8b817..083b8c42210 100644 --- a/apps/web/src/pages/Explore/index.tsx +++ b/apps/web/src/pages/Explore/index.tsx @@ -1,5 +1,4 @@ -import { BrowserEvent, InterfaceElementName, InterfacePageName, SharedEventName } from '@uniswap/analytics-events' -import { Trace, TraceEvent } from 'analytics' +import { InterfaceElementName, InterfacePageName, SharedEventName } from '@uniswap/analytics-events' import { TopPoolTable } from 'components/Pools/PoolTable/PoolTable' import { AutoRow } from 'components/Row' import { TopTokensTable } from 'components/Tokens/TokenTable' @@ -20,6 +19,7 @@ import { manualChainOutageAtom } from 'featureFlags/flags/outageBanner' import { getTokenExploreURL, isBackendSupportedChain } from 'graphql/data/util' import { useOnGlobalChainSwitch } from 'hooks/useGlobalChainSwitch' import { useResetAtom } from 'jotai/utils' +import Trace from 'uniswap/src/features/telemetry/Trace' import { useExploreParams } from './redirects' import RecentTransactions from './tables/RecentTransactions' @@ -81,23 +81,24 @@ interface Page { title: React.ReactNode key: ExploreTab component: () => JSX.Element - loggingElementName: string + loggingElementName: InterfaceElementName } + const Pages: Array = [ { - title: Tokens, + title: , key: ExploreTab.Tokens, component: TopTokensTable, loggingElementName: InterfaceElementName.EXPLORE_TOKENS_TAB, }, { - title: Pools, + title: , key: ExploreTab.Pools, component: TopPoolTable, loggingElementName: InterfaceElementName.EXPLORE_POOLS_TAB, }, { - title: Transactions, + title: , key: ExploreTab.Transactions, component: RecentTransactions, loggingElementName: InterfaceElementName.EXPLORE_TRANSACTIONS_TAB, @@ -111,7 +112,9 @@ const Explore = ({ initialTab }: { initialTab?: ExploreTab }) => { const initialKey: number = useMemo(() => { const key = initialTab && Pages.findIndex((page) => page.key === initialTab) - if (!key || key === -1) return 0 + if (!key || key === -1) { + return 0 + } return key }, [initialTab]) @@ -154,20 +157,16 @@ const Explore = ({ initialTab }: { initialTab?: ExploreTab }) => { ) return ( - + {Pages.map(({ title, loggingElementName, key }, index) => { return ( - @@ -178,7 +177,7 @@ const Explore = ({ initialTab }: { initialTab?: ExploreTab }) => { {title} - + ) })} diff --git a/apps/web/src/pages/Explore/tables/RecentTransactions.tsx b/apps/web/src/pages/Explore/tables/RecentTransactions.tsx index 25488f66f69..c82601bf9e6 100644 --- a/apps/web/src/pages/Explore/tables/RecentTransactions.tsx +++ b/apps/web/src/pages/Explore/tables/RecentTransactions.tsx @@ -70,7 +70,7 @@ export default function RecentTransactions() { )} - Time + @@ -98,7 +98,7 @@ export default function RecentTransactions() { isSticky={true} /> - Type + @@ -111,7 +111,11 @@ export default function RecentTransactions() { - {transaction.getValue?.().type === PoolTransactionType.Swap ? for : and} + {transaction.getValue?.().type === PoolTransactionType.Swap ? ( + + ) : ( + + )} @@ -136,7 +140,7 @@ export default function RecentTransactions() { header: () => ( - Token amount + ), @@ -158,7 +162,7 @@ export default function RecentTransactions() { header: () => ( - Token amount + ), @@ -180,7 +184,7 @@ export default function RecentTransactions() { header: () => ( - Wallet + ), diff --git a/apps/web/src/pages/Landing/Fold.tsx b/apps/web/src/pages/Landing/Fold.tsx index d6a7e8058ba..8f3d873f950 100644 --- a/apps/web/src/pages/Landing/Fold.tsx +++ b/apps/web/src/pages/Landing/Fold.tsx @@ -21,10 +21,8 @@ const Container = styled.div` const Fold = forwardRef(function Fold(props, scrollAnchor) { return ( - -
- -
+ +