Compare commits

...

3 Commits

Author SHA1 Message Date
Charles Bachmeier
d6865b033a
feat: add feature flag for avax ()
* feat: add feature flag for avax

* add new files

* block swapping when user manually changes chain

* rule of hooks

* remove comment
2023-07-10 17:05:19 -04:00
UL Service Account
e5dff197a9 ci: add global CODEOWNERS 2023-07-07 19:02:47 +00:00
UL Service Account
3b30410284 ci(t9n): download translations from crowdin 2023-07-07 19:02:47 +00:00
45 changed files with 115164 additions and 12 deletions

1
CODEOWNERS Normal file

@ -0,0 +1 @@
@uniswap/web-admins

@ -4,6 +4,7 @@ import { computePoolAddress, Pool, Position } from '@uniswap/v3-sdk'
import { DEFAULT_ERC20_DECIMALS } from 'constants/tokens'
import { BigNumber } from 'ethers/lib/ethers'
import { Interface } from 'ethers/lib/utils'
import { useFilterChainsForAvalanche } from 'featureFlags/flags/avalanche'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { PositionDetails } from 'types/position'
import { NonfungiblePositionManager, UniswapInterfaceMulticall } from 'types/v3'
@ -61,10 +62,11 @@ type UseMultiChainPositionsData = { positions?: PositionInfo[]; loading: boolean
* @returns positions, fees
*/
export default function useMultiChainPositions(account: string, chains = DEFAULT_CHAINS): UseMultiChainPositionsData {
const pms = useV3ManagerContracts(chains)
const multicalls = useInterfaceMulticallContracts(chains)
const gatedChains = useFilterChainsForAvalanche(chains)
const pms = useV3ManagerContracts(gatedChains)
const multicalls = useInterfaceMulticallContracts(gatedChains)
const getTokens = useGetCachedTokens(chains)
const getTokens = useGetCachedTokens(gatedChains)
const poolAddressCache = usePoolAddressCache()
const [cachedPositions, setPositions] = useCachedPositions(account)

@ -1,4 +1,5 @@
import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'featureFlags'
import { useAvalancheFlag } from 'featureFlags/flags/avalanche'
import { DetailsV2Variant, useDetailsV2Flag } from 'featureFlags/flags/nftDetails'
import { useRoutingAPIForPriceFlag } from 'featureFlags/flags/priceRoutingApi'
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
@ -214,6 +215,12 @@ export default function FeatureFlagModal() {
featureFlag={FeatureFlag.routingAPIPrice}
label="Use the URA or routing-api for price fetches"
/>
<FeatureFlagOption
variant={BaseVariant}
value={useAvalancheFlag()}
featureFlag={FeatureFlag.avalanche}
label="Enable Avalanche chain"
/>
<FeatureFlagGroup name="Debug">
<FeatureFlagOption
variant={TraceJsonRpcVariant}

@ -8,6 +8,7 @@ import { ConnectionType } from 'connection/types'
import { WalletConnectV2 } from 'connection/WalletConnectV2'
import { getChainInfo } from 'constants/chainInfo'
import { L1_CHAIN_IDS, L2_CHAIN_IDS, TESTNET_CHAIN_IDS, UniWalletSupportedChains } from 'constants/chains'
import { useIsAvalancheEnabled } from 'featureFlags/flags/avalanche'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import useSelectChain from 'hooks/useSelectChain'
import useSyncChainQuery from 'hooks/useSyncChainQuery'
@ -50,6 +51,7 @@ export const ChainSelector = ({ leftAlign }: ChainSelectorProps) => {
const { chainId } = useWeb3React()
const [isOpen, setIsOpen] = useState<boolean>(false)
const isMobile = useIsMobile()
const isAvalancheEnabled = useIsAvalancheEnabled()
const theme = useTheme()
@ -58,7 +60,8 @@ export const ChainSelector = ({ leftAlign }: ChainSelectorProps) => {
const [supportedChains, unsupportedChains] = useMemo(() => {
const { supported, unsupported } = NETWORK_SELECTOR_CHAINS.filter(
(chain: number) => showTestnets || !TESTNET_CHAIN_IDS.includes(chain)
(chain: number) =>
(showTestnets || !TESTNET_CHAIN_IDS.includes(chain)) && (isAvalancheEnabled || chain !== ChainId.AVALANCHE)
).reduce(
(acc, chain) => {
if (walletSupportsChain.includes(chain)) {
@ -71,7 +74,7 @@ export const ChainSelector = ({ leftAlign }: ChainSelectorProps) => {
{ supported: [], unsupported: [] } as Record<string, ChainId[]>
)
return [supported, unsupported]
}, [showTestnets, walletSupportsChain])
}, [isAvalancheEnabled, showTestnets, walletSupportsChain])
const ref = useRef<HTMLDivElement>(null)
const modalRef = useRef<HTMLDivElement>(null)
@ -98,7 +101,7 @@ export const ChainSelector = ({ leftAlign }: ChainSelectorProps) => {
return null
}
const isSupported = !!info
const isSupported = !!info && (isAvalancheEnabled || chainId !== ChainId.AVALANCHE)
const dropdown = (
<NavDropdown top="56" left={leftAlign ? '0' : 'auto'} right={leftAlign ? 'auto' : '0'} ref={modalRef}>

@ -6,6 +6,7 @@ import { useWeb3React } from '@web3-react/core'
import clsx from 'clsx'
import Badge from 'components/Badge'
import { getChainInfo } from 'constants/chainInfo'
import { useFilterChainsForAvalanche } from 'featureFlags/flags/avalanche'
import { HistoryDuration, SafetyLevel } from 'graphql/data/__generated__/types-and-hooks'
import { useTrendingCollections } from 'graphql/data/nft/TrendingCollections'
import { SearchToken } from 'graphql/data/SearchTokens'
@ -356,8 +357,8 @@ export const SearchBarDropdown = ({
trendingCollectionsAreLoading,
shouldDisableNFTRoutes,
])
const showChainComingSoonBadge = chainId && BACKEND_NOT_YET_SUPPORTED_CHAIN_IDS.includes(chainId) && !isLoading
const gatedUnsupportedChains = useFilterChainsForAvalanche([...BACKEND_NOT_YET_SUPPORTED_CHAIN_IDS])
const showChainComingSoonBadge = chainId && gatedUnsupportedChains.includes(chainId) && !isLoading
const logoUri = getChainInfo(chainId)?.logoUrl
return (

@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro'
import { ChainId } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { getChainInfo } from 'constants/chainInfo'
import { useIsAvalancheEnabled } from 'featureFlags/flags/avalanche'
import { ArrowUpRight } from 'react-feather'
import styled from 'styled-components/macro'
import { ExternalLink, HideSmall } from 'theme'
@ -159,13 +160,14 @@ function shouldShowAlert(chainId: number | undefined): chainId is NetworkAlertCh
export function NetworkAlert() {
const { chainId } = useWeb3React()
const [darkMode] = useDarkModeManager()
const isAvalancheEnabled = useIsAvalancheEnabled()
if (!shouldShowAlert(chainId)) {
return null
}
const chainInfo = getChainInfo(chainId)
if (!chainInfo) return null
if (!chainInfo || (!isAvalancheEnabled && chainId === ChainId.AVALANCHE)) return null
const { label, logoUrl, bridge } = chainInfo
const textColor = TEXT_COLORS[chainId]

@ -1,5 +1,6 @@
import Badge from 'components/Badge'
import { getChainInfo } from 'constants/chainInfo'
import { useFilterChainsForAvalanche } from 'featureFlags/flags/avalanche'
import {
BACKEND_NOT_YET_SUPPORTED_CHAIN_IDS,
BACKEND_SUPPORTED_CHAINS,
@ -117,6 +118,7 @@ export default function NetworkFilter() {
const toggleMenu = useToggleModal(ApplicationModal.NETWORK_FILTER)
useOnClickOutside(node, open ? toggleMenu : undefined)
const navigate = useNavigate()
const gatedUnsupportedChains = useFilterChainsForAvalanche([...BACKEND_NOT_YET_SUPPORTED_CHAIN_IDS])
const { chainName } = useParams<{ chainName?: string }>()
const currentChainName = validateUrlChainParam(chainName)
@ -169,7 +171,7 @@ export default function NetworkFilter() {
</InternalLinkMenuItem>
)
})}
{BACKEND_NOT_YET_SUPPORTED_CHAIN_IDS.map((network) => {
{gatedUnsupportedChains.map((network) => {
const chainInfo = getChainInfo(network)
return (
<InternalLinkMenuItem

@ -0,0 +1,16 @@
import { ChainId } from '@uniswap/sdk-core'
import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
export function useAvalancheFlag(): BaseVariant {
return useBaseFlag(FeatureFlag.avalanche)
}
export function useIsAvalancheEnabled(): boolean {
return useAvalancheFlag() === BaseVariant.Enabled
}
export function useFilterChainsForAvalanche(chains: ChainId[]): ChainId[] {
const isAvalancheEnabled = useIsAvalancheEnabled()
return chains.filter((chain) => chain !== ChainId.AVALANCHE || isAvalancheEnabled)
}

@ -13,6 +13,7 @@ export enum FeatureFlag {
debounceSwapQuote = 'debounce_swap_quote',
nativeUsdcArbitrum = 'web_usdc_arbitrum',
routingAPIPrice = 'routing_api_price',
avalanche = 'avalanche',
}
interface FeatureFlagsContextType {

3488
src/locales/af-ZA.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/ar-SA.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/ca-ES.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/cs-CZ.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/da-DK.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/de-DE.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/el-GR.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/es-ES.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/fi-FI.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/fr-FR.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/he-IL.po Normal file

File diff suppressed because it is too large Load Diff

3489
src/locales/hu-HU.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/id-ID.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/it-IT.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/ja-JP.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/ko-KR.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/nl-NL.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/no-NO.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/pl-PL.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/pt-BR.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/pt-PT.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/ro-RO.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/ru-RU.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/sl-SI.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/sr-SP.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/sv-SE.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/sw-TZ.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/th-TH.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/tr-TR.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/uk-UA.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/vi-VN.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/zh-CN.po Normal file

File diff suppressed because it is too large Load Diff

3488
src/locales/zh-TW.po Normal file

File diff suppressed because it is too large Load Diff

@ -22,6 +22,7 @@ import SwapDetailsDropdown from 'components/swap/SwapDetailsDropdown'
import TokenSafetyModal from 'components/TokenSafety/TokenSafetyModal'
import { getChainInfo } from 'constants/chainInfo'
import { asSupportedChain, isSupportedChain } from 'constants/chains'
import { useIsAvalancheEnabled } from 'featureFlags/flags/avalanche'
import useENSAddress from 'hooks/useENSAddress'
import { useMaxAmountIn } from 'hooks/useMaxAmountIn'
import usePermit2Allowance, { AllowanceState } from 'hooks/usePermit2Allowance'
@ -135,7 +136,7 @@ const TRADE_STRING = 'SwapRouter'
export default function SwapPage({ className }: { className?: string }) {
const { chainId: connectedChainId } = useWeb3React()
const loadedUrlParams = useDefaultsFromURLSearch()
const isAvalancheEnabled = useIsAvalancheEnabled()
const location = useLocation()
return (
@ -148,6 +149,7 @@ export default function SwapPage({ className }: { className?: string }) {
[Field.INPUT]: { currencyId: loadedUrlParams?.[Field.INPUT]?.currencyId },
[Field.OUTPUT]: { currencyId: loadedUrlParams?.[Field.OUTPUT]?.currencyId },
}}
disableTokenInputs={!isAvalancheEnabled && connectedChainId === ChainId.AVALANCHE}
/>
<NetworkAlert />
</PageWrapper>

@ -1,6 +1,7 @@
import { Trans } from '@lingui/macro'
import { ChainId, Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { useIsAvalancheEnabled } from 'featureFlags/flags/avalanche'
import useAutoSlippageTolerance from 'hooks/useAutoSlippageTolerance'
import { useBestTrade } from 'hooks/useBestTrade'
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
@ -88,6 +89,7 @@ export function useDerivedSwapInfo(
autoSlippage: Percent
} {
const { account } = useWeb3React()
const isAvalancheEnabled = useIsAvalancheEnabled()
const {
independentField,
@ -97,7 +99,10 @@ export function useDerivedSwapInfo(
recipient,
} = state
const inputCurrency = useCurrency(inputCurrencyId, chainId)
const inputCurrency = useCurrency(
isAvalancheEnabled || chainId !== ChainId.AVALANCHE ? inputCurrencyId : undefined,
chainId
)
const outputCurrency = useCurrency(outputCurrencyId, chainId)
const recipientLookup = useENS(recipient ?? undefined)
const to: string | null = (recipient === null ? account : recipientLookup.address) ?? null

@ -1,5 +1,6 @@
import { ChainId } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { useIsAvalancheEnabled } from 'featureFlags/flags/avalanche'
import { useIsNftPage } from 'hooks/useIsNftPage'
import { useEffect } from 'react'
import { useDarkModeManager } from 'theme/components/ThemeToggle'
@ -31,6 +32,7 @@ export default function RadialGradientByChainUpdater(): null {
const { chainId } = useWeb3React()
const [darkMode] = useDarkModeManager()
const isNftPage = useIsNftPage()
const isAvalancheEnabled = useIsAvalancheEnabled()
// manage background color
useEffect(() => {
@ -97,6 +99,9 @@ export default function RadialGradientByChainUpdater(): null {
break
}
case ChainId.AVALANCHE: {
if (!isAvalancheEnabled) {
break
}
setBackground(backgroundResetStyles)
const avaxLightGradient =
'radial-gradient(100% 100% at 50% 0%, rgba(255, 251, 242, 0.8) 0%, rgba(255, 244, 249, 0.6958) 50.52%, rgba(255, 255, 255, 0) 100%), #FFFFFF'