diff --git a/.github/workflows/schedule.yml b/.github/workflows/schedule.yml index fd159f85b8..8649a988e8 100644 --- a/.github/workflows/schedule.yml +++ b/.github/workflows/schedule.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - network: ['Ethereum', 'Arbitrum', 'Optimism', 'Avalanche', 'BNB'] + network: ['Ethereum', 'Arbitrum', 'Optimism', 'Avalanche', 'BNB Chain'] steps: - name: Trigger Code Checkout uses: actions/checkout@v3 diff --git a/.nvmrc b/.nvmrc index 2f3b977c5b..c946e1df49 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v18.15.0 \ No newline at end of file +v20.9.0 \ No newline at end of file diff --git a/cypress/e2e/pages/cross-chain.po.cy.ts b/cypress/e2e/pages/cross-chain.po.cy.ts new file mode 100644 index 0000000000..52f647f14b --- /dev/null +++ b/cypress/e2e/pages/cross-chain.po.cy.ts @@ -0,0 +1,50 @@ +import { NETWORK_LIST } from "../selectors/constants.cy" +import { CrossChainLocators, NetworkLocators } from "../selectors/selectors.cy" + +export const CrossChain = { + + closeUnderstandPopup() { + cy.get(CrossChainLocators.btnUnderstand).click() + }, + + selectNetworkIn(networkName: string) { + cy.get(CrossChainLocators.btnNetworkIn).click() + cy.get(NetworkLocators.btnNetwork).contains(networkName).click({ force: true }) + + }, + + selectNetworkOut(networkName: string) { + cy.get(CrossChainLocators.btnNetworkOut).click() + cy.get(NetworkLocators.btnNetwork).contains(networkName).click({ force: true }) + }, + + changeNetwork(oldNetwork: string[]) { + let random = 0 + do { + random = Math.floor(Math.random() * NETWORK_LIST.length) + } while (oldNetwork.includes(NETWORK_LIST[random]) === true) + + return NETWORK_LIST[random] + }, + + checkLoadedPage() { + return cy.get(CrossChainLocators.rechartsSurface, { timeout: 20000 }).should(() => { }).then($obj => { + if ($obj.length > 0) { + return true + } + return false + }) + }, + + getCurrentNetworkIn() { + return cy.get(CrossChainLocators.btnNetworkIn).invoke('text').then(network => { + return network + }) + }, + + getCurrentNetworkOut() { + return cy.get(CrossChainLocators.btnNetworkOut).invoke('text').then(network => { + return network + }) + }, +} diff --git a/cypress/e2e/pages/limit-order.po.cy.ts b/cypress/e2e/pages/limit-order.po.cy.ts index 708437da71..de95c61aa1 100644 --- a/cypress/e2e/pages/limit-order.po.cy.ts +++ b/cypress/e2e/pages/limit-order.po.cy.ts @@ -5,6 +5,19 @@ export interface myCallbackType { } export const LimitOder = { + checkGetStartedDisplay() { + return cy.get(LimitOrderLocators.btnGetStarted, { timeout: 10000 }).should(() => { }).then($obj => { + if ($obj.length > 0) { + return true + } + return false + }) + }, + + clickGetStarted() { + cy.get(LimitOrderLocators.btnGetStarted, { timeout: 10000 }).click({ force: true }) + }, + selectTokenSell(): TokenCatalog { cy.selectToken(LimitOrderLocators.dropdownTokenSell) return new TokenCatalog() diff --git a/cypress/e2e/pages/swap-page.po.cy.ts b/cypress/e2e/pages/swap-page.po.cy.ts index a45936195a..86e69682d7 100644 --- a/cypress/e2e/pages/swap-page.po.cy.ts +++ b/cypress/e2e/pages/swap-page.po.cy.ts @@ -1,4 +1,4 @@ -import { HeaderLocators, LimitOrderLocators, NetworkLocators, SwapPageLocators, TokenCatalogLocators, WalletLocators } from "../selectors/selectors.cy" +import { CrossChainLocators, HeaderLocators, LimitOrderLocators, NetworkLocators, SwapPageLocators, TokenCatalogLocators, WalletLocators } from "../selectors/selectors.cy" export interface myCallbackType { (myArgument: T): void @@ -41,6 +41,10 @@ export const SwapPage = { cy.get(LimitOrderLocators.btnLimit).click() }, + goToCrossChain() { + cy.get(CrossChainLocators.btnCrossChain).click() + }, + goToFarmPage() { cy.get(HeaderLocators.dropdownEarn).click({ force: true }) cy.get(HeaderLocators.lblFarms).click({ force: true }) diff --git a/cypress/e2e/selectors/constants.cy.ts b/cypress/e2e/selectors/constants.cy.ts index f015f87d6c..f50ff81317 100644 --- a/cypress/e2e/selectors/constants.cy.ts +++ b/cypress/e2e/selectors/constants.cy.ts @@ -19,6 +19,8 @@ export const TOKEN_SYMBOLS = { 'BNB': ['RICE', 'DAI', 'USDT', 'USDC', 'MAI'] } +export const NETWORK_LIST = ['Ethereum', 'Arbitrum', 'Optimism', 'Avalanche', 'BNB Chain', 'Polygon PoS', 'Fantom', 'Linea', 'Base'] + export const UNWHITELIST_TOKENS = { "Ethereum": [ diff --git a/cypress/e2e/selectors/selectors.cy.ts b/cypress/e2e/selectors/selectors.cy.ts index b36d6b9868..0ad9015779 100644 --- a/cypress/e2e/selectors/selectors.cy.ts +++ b/cypress/e2e/selectors/selectors.cy.ts @@ -28,7 +28,16 @@ export const LimitOrderLocators = { btnLimit: '[data-testid=limit-button]', txtSellingRate: '[data-testid=input-selling-rate]', lblBalanceIn: '[data-testid=limit-order-input-tokena] [data-testid=balance]', - lblErrorMessage: '[data-testid=error-message]' + lblErrorMessage: '[data-testid=error-message]', + btnGetStarted: '[data-testid=get-started-button]' +} + +export const CrossChainLocators = { + btnCrossChain: '[data-testid=cross-chain-tab]', + btnNetworkIn: '[data-testid=swap-currency-input] [data-testid=network-button]', + btnNetworkOut: '[data-testid=swap-currency-output] [data-testid=network-button]', + btnUnderstand: '[data-testid=understand-button]', + rechartsSurface: '.recharts-surface' //it's in the library so don't use data-testid } export const WalletLocators = { @@ -40,7 +49,7 @@ export const WalletLocators = { export const NetworkLocators = { btnSelectNetwork: '[data-testid=select-network]', - btnNetwork: '[data-testid=network-button]', + btnNetwork: '[data-testid=network-list]', } export const HeaderLocators = { diff --git a/cypress/e2e/specs/connect-wallet.e2e.cy.ts b/cypress/e2e/specs/connect-wallet.e2e.cy.ts index 3de9e0e8da..34f9afabbb 100644 --- a/cypress/e2e/specs/connect-wallet.e2e.cy.ts +++ b/cypress/e2e/specs/connect-wallet.e2e.cy.ts @@ -11,13 +11,13 @@ describe('Metamask Extension tests', { tags: TAG.regression }, () => { SwapPage.connectWallet() }) - it.skip('Redirects to swap page when a user has already connected a wallet', () => { + it('Redirects to swap page when a user has already connected a wallet', () => { cy.acceptMetamaskAccess() SwapPage.getStatusConnectedWallet() cy.url().should('include', '/swap') }) - it.skip('Should approve permission to switch network', () => { + it('Should approve permission to switch network', () => { if (NETWORK !== DEFAULT_NETWORK) { SwapPage.getStatusConnectedWallet() wallet.selectNetwork(NETWORK) diff --git a/cypress/e2e/specs/cross-chain.e2e.cy.ts b/cypress/e2e/specs/cross-chain.e2e.cy.ts new file mode 100644 index 0000000000..5580eeb4fb --- /dev/null +++ b/cypress/e2e/specs/cross-chain.e2e.cy.ts @@ -0,0 +1,37 @@ +import { CrossChain } from "../pages/cross-chain.po.cy" +import { SwapPage } from "../pages/swap-page.po.cy" +import { DEFAULT_URL, NETWORK, TAG } from "../selectors/constants.cy" + + +describe(`Cross-chain on ${NETWORK}`, { tags: TAG.regression }, () => { + beforeEach(() => { + SwapPage.open(DEFAULT_URL) + SwapPage.goToCrossChain() + CrossChain.checkLoadedPage().then((checked) => { + if (checked === true) { + CrossChain.closeUnderstandPopup() + } + }) + }) + + describe('Select network', () => { + it('The network should be changed successfully', () => { + const networkIn = CrossChain.changeNetwork([NETWORK]) + CrossChain.selectNetworkIn(networkIn) + CrossChain.getCurrentNetworkIn().then((currentNetworkIn) => { + expect(currentNetworkIn).to.equal(networkIn) + }) + + CrossChain.getCurrentNetworkOut().then((currentNetworkOut) => { + const networkOut = CrossChain.changeNetwork([networkIn, currentNetworkOut]) + cy.wait(1000) + CrossChain.selectNetworkOut(networkOut) + CrossChain.getCurrentNetworkOut().then((currentNetworkOut) => { + expect(currentNetworkOut).to.equal(networkOut) + }) + + }) + }) + + }) +}) \ No newline at end of file diff --git a/cypress/e2e/specs/limit-order.e2e.cy.ts b/cypress/e2e/specs/limit-order.e2e.cy.ts index 5bd9d4e22c..19310474c8 100644 --- a/cypress/e2e/specs/limit-order.e2e.cy.ts +++ b/cypress/e2e/specs/limit-order.e2e.cy.ts @@ -4,14 +4,17 @@ import { DEFAULT_URL, NETWORK, NORESULTS_TEXT, NOTOKENS_TEXT, TAG, TOKEN_SYMBOLS const tokenSymbols = TOKEN_SYMBOLS[NETWORK] - const tokenCatalog = new TokenCatalog(); - describe(`Limit Order on ${NETWORK}`, { tags: TAG.regression }, () => { beforeEach(() => { SwapPage.open(DEFAULT_URL) SwapPage.goToLimitOrder() + LimitOder.checkGetStartedDisplay().then((checked) => { + if (checked === true) { + LimitOder.clickGetStarted() + } + }) }) describe('Add/remove/select token with favorite tokens list', () => { diff --git a/cypress/support/connectWalletCommands.ts b/cypress/support/connectWalletCommands.ts index 556542d341..80959f22e0 100644 --- a/cypress/support/connectWalletCommands.ts +++ b/cypress/support/connectWalletCommands.ts @@ -12,6 +12,7 @@ declare global { } Cypress.Commands.add('connectWallet', () => { - cy.get(WalletLocators.chkAcceptTerm).click() + // feature changed => temporary comment + // cy.get(WalletLocators.chkAcceptTerm).click() cy.get(WalletLocators.btnMetaMask).click() }) diff --git a/package.json b/package.json index 20d3bc1ac8..4601d8a960 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,6 @@ "axios": "1.2.1", "base64-js": "^1.5.1", "buffer": "^6.0.3", - "cids": "^1.1.9", "crypto-js": "4.1.1", "d3": "^7.6.1", "dayjs": "^1.11.6", @@ -97,8 +96,6 @@ "lightweight-charts": "^3.3.0", "memoize-one": "^6.0.0", "mixpanel-browser": "^2.45.0", - "multicodec": "^2.1.3", - "multihashes": "^3.1.2", "node-vibrant": "^3.1.6", "numeral": "^2.0.6", "patch-package": "^7.0.0", @@ -157,7 +154,6 @@ "@types/d3": "^7.1.0", "@types/dompurify": "^3.0.3", "@types/mixpanel-browser": "^2.38.0", - "@types/multicodec": "^1.0.0", "@types/node": "^20.8.8", "@types/numeral": "^2.0.0", "@types/react": "^18.0.15", @@ -208,4 +204,4 @@ "@lingui/core": "3.14.0", "@lingui/conf": "3.16.0" } -} \ No newline at end of file +} diff --git a/src/components/CurrencyInputPanel/CurrencyInputPanelBridge.tsx b/src/components/CurrencyInputPanel/CurrencyInputPanelBridge.tsx index 50e0310f4a..4f929ce054 100644 --- a/src/components/CurrencyInputPanel/CurrencyInputPanelBridge.tsx +++ b/src/components/CurrencyInputPanel/CurrencyInputPanelBridge.tsx @@ -40,6 +40,7 @@ interface CurrencyInputPanelBridgeProps { usdValue?: string isCrossChain?: boolean tooltipNotSupportChain?: string + dataTestId?: string } const noop = () => { @@ -80,6 +81,7 @@ export default function CurrencyInputPanelBridge({ usdValue, isCrossChain, tooltipNotSupportChain, + dataTestId, }: CurrencyInputPanelBridgeProps) { const [modalOpen, setModalOpen] = useState(false) const { account } = useActiveWeb3React() @@ -111,7 +113,7 @@ export default function CurrencyInputPanelBridge({ return (
- + ` @@ -27,11 +24,6 @@ const StyledLogo = styled(Logo)<{ size: string }>` object-fit: contain; ` -export const useGetNativeTokenLogo = (chainId: ChainId | undefined) => { - const whitelistTokens = useAllTokens(false, chainId) - return whitelistTokens[ETHER_ADDRESS]?.logoURI || (chainId ? NETWORKS_INFO[chainId].nativeToken.logo : '') -} - function CurrencyLogo({ currency, size = '24px', @@ -56,7 +48,6 @@ function CurrencyLogo({ const logoURI = currency instanceof WrappedTokenInfo ? currency?.logoURI : undefined const uriLocations = useHttpLocations(wrapWithProxy(logoURI)) - const nativeLogo = useGetNativeTokenLogo(currency?.chainId) const srcs: string[] = useMemo(() => { if (currency?.isNative) return [] @@ -72,7 +63,14 @@ function CurrencyLogo({ }, [currency, logoURI, uriLocations, wrapWithProxy]) if (currency?.isNative) { - return + return ( + + ) } return diff --git a/src/components/Header/web3/NetworkModal/index.tsx b/src/components/Header/web3/NetworkModal/index.tsx index 5b86a5f45e..020f6437e1 100644 --- a/src/components/Header/web3/NetworkModal/index.tsx +++ b/src/components/Header/web3/NetworkModal/index.tsx @@ -290,6 +290,7 @@ export default function NetworkModal({ } }} id={CHAINS_DROPZONE_ID} + data-testid="network-list" style={{ position: 'relative', minHeight: '50px' }} > diff --git a/src/components/Header/web3/WalletModal/index.tsx b/src/components/Header/web3/WalletModal/index.tsx index 0986a50436..4bd1254255 100644 --- a/src/components/Header/web3/WalletModal/index.tsx +++ b/src/components/Header/web3/WalletModal/index.tsx @@ -32,6 +32,7 @@ import { useWalletModalToggle, } from 'state/application/hooks' import { useIsConnectingWallet } from 'state/authen/hooks' +import { useIsAcceptedTerm } from 'state/user/hooks' import { ExternalLink } from 'theme' import { isEVMWallet, isOverriddenWallet, isSolanaWallet } from 'utils' @@ -61,7 +62,7 @@ const ContentWrapper = styled.div` ` const TermAndCondition = styled.div` - padding: 8px 16px; + padding: 8px; font-size: 12px; font-weight: 500; line-height: 16px; @@ -157,6 +158,8 @@ export default function WalletModal() { const previousAccount = usePrevious(account) + const [isAcceptedTerm, setIsAcceptedTerm] = useIsAcceptedTerm() + const location = useLocation() const { mixpanelHandler } = useMixpanel() @@ -313,19 +316,33 @@ export default function WalletModal() { {(walletView === WALLET_VIEWS.ACCOUNT || walletView === WALLET_VIEWS.CHANGE_WALLET) && ( - + { + if (!isAcceptedTerm) { + mixpanelHandler(MIXPANEL_TYPE.WALLET_CONNECT_ACCEPT_TERM_CLICK) + } + setIsAcceptedTerm(!isAcceptedTerm) + }} + > + - - By connecting a wallet, you accept{' '} - e.stopPropagation()}> - KyberSwap‘s Terms of Use - {' '} - and consent to its{' '} - e.stopPropagation()}> - Privacy Policy - - . Last updated: {dayjs(TERM_FILES_PATH.VERSION).format('DD MMM YYYY')} - + Accept {' '} + e.stopPropagation()}> + KyberSwap‘s Terms of Use + {' '} + and{' '} + e.stopPropagation()}> + Privacy Policy + + {'. '} + + Last updated: {dayjs(TERM_FILES_PATH.VERSION).format('DD MMM YYYY')} + )} diff --git a/src/components/Logo/index.tsx b/src/components/Logo/index.tsx index f3b1b4b02a..a1a0f2e2b8 100644 --- a/src/components/Logo/index.tsx +++ b/src/components/Logo/index.tsx @@ -4,9 +4,9 @@ import { HelpCircle } from 'react-feather' import { ImageProps } from 'rebass' import styled from 'styled-components' -import { useGetNativeTokenLogo } from 'components/CurrencyLogo' import { NETWORKS_INFO } from 'hooks/useChainsConfig' import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo' +import { getNativeTokenLogo } from 'utils' const BAD_SRCS: { [tokenAddress: string]: true } = {} @@ -51,7 +51,7 @@ export function TokenLogoWithChain(data: any) { const { tokenLogo: tokenLogoParam, chainId: chainParam, size, currency } = data const chainId: ChainId = currency?.chainId || chainParam - const nativeLogo = useGetNativeTokenLogo(chainId) + const nativeLogo = getNativeTokenLogo(chainId) const tokenLogo = (currency?.isNative ? nativeLogo : currency?.logoURI) || tokenLogoParam const ratio = 0.7 const networkSize = ratio * parseInt(size + '') diff --git a/src/components/Menu/FaucetModal.tsx b/src/components/Menu/FaucetModal.tsx index 6e60406dd8..60e7a1a84e 100644 --- a/src/components/Menu/FaucetModal.tsx +++ b/src/components/Menu/FaucetModal.tsx @@ -8,7 +8,6 @@ import styled from 'styled-components' import { NotificationType } from 'components/Announcement/type' import { ButtonPrimary } from 'components/Button' -import { useGetNativeTokenLogo } from 'components/CurrencyLogo' import Logo from 'components/Logo' import Modal from 'components/Modal' import { RowBetween } from 'components/Row' @@ -21,7 +20,7 @@ import useTheme from 'hooks/useTheme' import { ApplicationModal } from 'state/application/actions' import { useModalOpen, useNotify, useToggleModal, useWalletModalToggle } from 'state/application/hooks' import { CloseIcon } from 'theme' -import { getTokenLogoURL, isAddress, shortenAddress } from 'utils' +import { getNativeTokenLogo, getTokenLogoURL, isAddress, shortenAddress } from 'utils' import { filterTokens } from 'utils/filtering' const AddressWrapper = styled.div` @@ -68,7 +67,7 @@ function FaucetModal() { return nativeToken }, [rewardData, chainId, account, allTokens]) - const nativeLogo = useGetNativeTokenLogo(chainId) + const nativeLogo = getNativeTokenLogo(chainId) const tokenLogo = useMemo(() => { if (!token) return if (token.isNative) return nativeLogo diff --git a/src/components/SearchModal/CurrencyList.tsx b/src/components/SearchModal/CurrencyList.tsx index 3ccc44b7f9..a64ad683d5 100644 --- a/src/components/SearchModal/CurrencyList.tsx +++ b/src/components/SearchModal/CurrencyList.tsx @@ -103,6 +103,8 @@ export function CurrencyRow({ usdBalance, hoverColor, hideBalance, + showLoading, + isFavorite, }: { showImported?: boolean showFavoriteIcon?: boolean @@ -119,40 +121,26 @@ export function CurrencyRow({ usdBalance?: number hoverColor?: string hideBalance?: boolean - customChainId?: ChainId + showLoading?: boolean + isFavorite?: boolean }) { - const { chainId, account } = useActiveWeb3React() const theme = useTheme() const nativeCurrency = useCurrencyConvertedToNative(currency || undefined) - const { favoriteTokens } = useUserFavoriteTokens(chainId) const onClickRemove = (e: React.MouseEvent) => { e.stopPropagation() removeImportedToken?.(currency as Token) } - const isFavorite = (() => { - if (!favoriteTokens) { - return false - } - - if (currency.isToken) { - const addr = (currency as Token).address ?? '' - const addresses = favoriteTokens ?? [] - return !!addresses?.includes(addr) || !!addresses?.includes(addr.toLowerCase()) - } - - return false - })() - const balanceComponent = hideBalance ? ( '******' ) : currencyBalance ? ( - ) : account ? ( + ) : showLoading ? ( ) : null const { symbol } = getDisplayTokenInfo(currency) + return ( importedToken.address === token.address) && !isTokenNative(currency, currency.chainId) - if (showImport && token && setImportToken) { return } @@ -261,8 +250,18 @@ function CurrencyList({ if (currency) { // whitelist + const isFavorite = (() => { + if (currency.isToken && favoriteTokens) { + const addr = (currency as Token).address ?? '' + return !!favoriteTokens?.includes(addr) || !!favoriteTokens?.includes(addr.toLowerCase()) + } + return false + })() + return ( loadMoreRows?.(), [loadMoreRows]) diff --git a/src/components/SwapForm/GasPriceNote.tsx b/src/components/SwapForm/GasPriceNote.tsx index d2a22dbf6e..1ba62568cd 100644 --- a/src/components/SwapForm/GasPriceNote.tsx +++ b/src/components/SwapForm/GasPriceNote.tsx @@ -1,41 +1,66 @@ import { ChainId } from '@kyberswap/ks-sdk-core' -import { Trans, t } from '@lingui/macro' +import { Trans } from '@lingui/macro' import { FC } from 'react' import { Text } from 'rebass' +import PriceImpactNote from 'components/SwapForm/PriceImpactNote' import WarningNote from 'components/WarningNote' import { useActiveWeb3React } from 'hooks' +import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel' import useTheme from 'hooks/useTheme' import { useSwitchPairToLimitOrder } from 'state/swap/hooks' +import { checkPriceImpact } from 'utils/prices' type Props = { gasUsd?: string + priceImpact?: number + isDegenMode: boolean } const GAS_USD_THRESHOLD = 20 -const GasPriceNote: FC = ({ gasUsd = 0 }) => { +const GasFeeAndPriceImpactNote: FC = ({ gasUsd = 0, priceImpact, isDegenMode }) => { const theme = useTheme() - const { chainId } = useActiveWeb3React() const switchToLimitOrder = useSwitchPairToLimitOrder() - if (+gasUsd < GAS_USD_THRESHOLD || chainId !== ChainId.MAINNET) return null + const { isHigh, isVeryHigh } = checkPriceImpact(priceImpact) + const { mixpanelHandler } = useMixpanel() + + if (+gasUsd < GAS_USD_THRESHOLD || chainId !== ChainId.MAINNET) + return + const limitOrderLink = ( + + + Do you want to make a{' '} + { + mixpanelHandler(MIXPANEL_TYPE.LO_CLICK_WARNING_IN_SWAP) + switchToLimitOrder() + }} + > + Limit Order + {' '} + instead? + + + ) return ( - - Do you want to make a{' '} - - Limit Order - {' '} - instead? - + {isHigh || isVeryHigh ? ( + Gas fees and Price Impact are very high. You will lose your funds. + ) : ( + Gas fees is very high. You will lose your funds. + )} } + longText={limitOrderLink} /> ) } -export default GasPriceNote +export default GasFeeAndPriceImpactNote diff --git a/src/components/SwapForm/PriceImpactNote.tsx b/src/components/SwapForm/PriceImpactNote.tsx index 00921740ed..87c3b4350e 100644 --- a/src/components/SwapForm/PriceImpactNote.tsx +++ b/src/components/SwapForm/PriceImpactNote.tsx @@ -6,6 +6,7 @@ import styled from 'styled-components' import Column from 'components/Column' import Row from 'components/Row' import WarningNote from 'components/WarningNote' +import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel' import useTheme from 'hooks/useTheme' import { useSwitchPairToLimitOrder } from 'state/swap/hooks' import { checkPriceImpact } from 'utils/prices' @@ -38,6 +39,7 @@ const PriceImpactNote: FC = ({ isDegenMode, priceImpact, showLimitOrderLi const priceImpactResult = checkPriceImpact(priceImpact) const theme = useTheme() const switchToLimitOrder = useSwitchPairToLimitOrder() + const { mixpanelHandler } = useMixpanel() if (typeof priceImpact !== 'number') { return null @@ -81,7 +83,15 @@ const PriceImpactNote: FC = ({ isDegenMode, priceImpact, showLimitOrderLi Do you want to make a{' '} - + { + mixpanelHandler(MIXPANEL_TYPE.LO_CLICK_WARNING_IN_SWAP) + switchToLimitOrder() + }} + > Limit Order {' '} instead? @@ -108,6 +118,7 @@ const PriceImpactNote: FC = ({ isDegenMode, priceImpact, showLimitOrderLi } longText={ + {limitOrderNote} {isDegenMode ? ( @@ -120,7 +131,6 @@ const PriceImpactNote: FC = ({ isDegenMode, priceImpact, showLimitOrderLi )} - {limitOrderNote} } /> diff --git a/src/components/SwapForm/index.tsx b/src/components/SwapForm/index.tsx index ead77a20ae..cf2b33be39 100644 --- a/src/components/SwapForm/index.tsx +++ b/src/components/SwapForm/index.tsx @@ -13,7 +13,7 @@ import AddressInputPanel from 'components/AddressInputPanel' import { Clock } from 'components/Icons' import { AutoRow } from 'components/Row' import SlippageWarningNote from 'components/SlippageWarningNote' -import GasPriceNote from 'components/SwapForm/GasPriceNote' +import GasFeeAndPriceImpactNote from 'components/SwapForm/GasPriceNote' import InputCurrencyPanel from 'components/SwapForm/InputCurrencyPanel' import OutputCurrencyPanel from 'components/SwapForm/OutputCurrencyPanel' import SlippageSettingGroup from 'components/SwapForm/SlippageSettingGroup' @@ -37,7 +37,6 @@ import { MEDIA_WIDTHS } from 'theme' import { DetailedRouteSummary } from 'types/route' import { currencyId } from 'utils/currencyId' -import PriceImpactNote from './PriceImpactNote' import RefreshButton from './RefreshButton' import ReverseTokenSelectionButton from './ReverseTokenSelectionButton' import SwapActionButton from './SwapActionButton' @@ -260,9 +259,11 @@ const SwapForm: React.FC = props => { {!isWrapOrUnwrap && } - - - + void }) { Learn more about our limit orders here. - + Get Started diff --git a/src/hooks/useENSContentHash.ts b/src/hooks/useENSContentHash.ts deleted file mode 100644 index 1605153d39..0000000000 --- a/src/hooks/useENSContentHash.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { namehash } from 'ethers/lib/utils' -import { useMemo } from 'react' - -import { useSingleCallResult } from 'state/multicall/hooks' -import isZero from 'utils/isZero' - -import { useENSRegistrarContract, useENSResolverContract } from './useContract' - -/** - * Does a lookup for an ENS name to find its contenthash. - */ -export default function useENSContentHash(ensName?: string | null): { loading: boolean; contenthash: string | null } { - const ensNodeArgument = useMemo(() => { - if (!ensName) return [undefined] - try { - return ensName ? [namehash(ensName)] : [undefined] - } catch (error) { - return [undefined] - } - }, [ensName]) - const registrarContract = useENSRegistrarContract() - const resolverAddressResult = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument) - const resolverAddress = resolverAddressResult.result?.[0] - const resolverContract = useENSResolverContract( - resolverAddress && isZero(resolverAddress) ? undefined : resolverAddress, - ) - const contenthash = useSingleCallResult(resolverContract, 'contenthash', ensNodeArgument) - - return useMemo( - () => ({ - contenthash: contenthash.result?.[0] ?? null, - loading: resolverAddressResult.loading || contenthash.loading, - }), - [contenthash.loading, contenthash.result, resolverAddressResult.loading], - ) -} diff --git a/src/hooks/useHttpLocations.ts b/src/hooks/useHttpLocations.ts index 2c4b45d2e6..6c39040797 100644 --- a/src/hooks/useHttpLocations.ts +++ b/src/hooks/useHttpLocations.ts @@ -1,20 +1,10 @@ import { useMemo } from 'react' import { EMPTY_ARRAY } from 'constants/index' -import contenthashToUri from 'utils/contenthashToUri' -import { parseENSAddress } from 'utils/parseENSAddress' import uriToHttp from 'utils/uriToHttp' -import useENSContentHash from './useENSContentHash' - export default function useHttpLocations(uri: string | undefined): string[] { - const ens = useMemo(() => (uri ? parseENSAddress(uri) : undefined), [uri]) - const resolvedContentHash = useENSContentHash(ens?.ensName) return useMemo(() => { - if (ens) { - return resolvedContentHash.contenthash ? uriToHttp(contenthashToUri(resolvedContentHash.contenthash)) : [] - } else { - return uri ? uriToHttp(uri) : EMPTY_ARRAY - } - }, [ens, resolvedContentHash.contenthash, uri]) + return uri ? uriToHttp(uri) : EMPTY_ARRAY + }, [uri]) } diff --git a/src/hooks/useMixpanel.ts b/src/hooks/useMixpanel.ts index 9a01ed4a96..6a319c0b11 100644 --- a/src/hooks/useMixpanel.ts +++ b/src/hooks/useMixpanel.ts @@ -206,6 +206,7 @@ export enum MIXPANEL_TYPE { LO_CLICK_CANCEL_TYPE, LO_CLICK_UPDATE_TYPE, LO_CLICK_GET_STARTED, + LO_CLICK_WARNING_IN_SWAP, // Wallet UI WUI_WALLET_CLICK, @@ -1138,6 +1139,10 @@ export default function useMixpanel(currencies?: { [field in Field]?: Currency } mixpanel.track('Limit Order - Get Started Click', payload) break } + case MIXPANEL_TYPE.LO_CLICK_WARNING_IN_SWAP: { + mixpanel.track('Limit Order - Warning in Swap Click', payload) + break + } case MIXPANEL_TYPE.WUI_WALLET_CLICK: { mixpanel.track('Wallet UI - Wallet Click') diff --git a/src/pages/Bridge/Disclaimer.tsx b/src/pages/Bridge/Disclaimer.tsx index 8ca9b0e6c8..4c07cbc1e9 100644 --- a/src/pages/Bridge/Disclaimer.tsx +++ b/src/pages/Bridge/Disclaimer.tsx @@ -91,7 +91,7 @@ export function DisclaimerCrossChain() { liability for any losses incurred. - + I Understand diff --git a/src/pages/Bridge/SelectNetwork.tsx b/src/pages/Bridge/SelectNetwork.tsx index c4b347d25e..315ccb0006 100644 --- a/src/pages/Bridge/SelectNetwork.tsx +++ b/src/pages/Bridge/SelectNetwork.tsx @@ -56,7 +56,7 @@ function Web3Network({ const { name } = selectedChainId ? NETWORKS_INFO[selectedChainId] : { name: t`Select a network` } return ( <> - chainIds.length && toggleNetworkModal()}> + chainIds.length && toggleNetworkModal()}> {selectedChainId && ( )} diff --git a/src/pages/CrossChain/SwapForm/index.tsx b/src/pages/CrossChain/SwapForm/index.tsx index 71886e42cd..f12c8c1edf 100644 --- a/src/pages/CrossChain/SwapForm/index.tsx +++ b/src/pages/CrossChain/SwapForm/index.tsx @@ -313,6 +313,7 @@ export default function SwapForm() { onMax={handleMaxInput} onCurrencySelect={onCurrencySelect} id="swap-currency-input" + dataTestId="swap-currency-input" usdValue={amountUsdIn ?? ''} /> @@ -342,6 +343,7 @@ export default function SwapForm() { } onCurrencySelect={onCurrencySelectDest} id="swap-currency-output" + dataTestId="swap-currency-output" usdValue={amountUsdOut ?? ''} />
diff --git a/src/pages/Farm/ElasticFarmv2/components/FarmCard.tsx b/src/pages/Farm/ElasticFarmv2/components/FarmCard.tsx index 760f00cc17..3de0fdcf6c 100644 --- a/src/pages/Farm/ElasticFarmv2/components/FarmCard.tsx +++ b/src/pages/Farm/ElasticFarmv2/components/FarmCard.tsx @@ -116,12 +116,15 @@ function FarmCard({ const currentTimestamp = Math.floor(Date.now() / 1000) const stakedPos = useUserFarmV2Info(farm.farmAddress, farm.fId) + let amountToken0 = CurrencyAmount.fromRawAmount(farm.token0.wrapped, 0) let amountToken1 = CurrencyAmount.fromRawAmount(farm.token1.wrapped, 0) stakedPos.forEach(item => { - amountToken0 = amountToken0.add(item.position.amount0) - amountToken1 = amountToken1.add(item.position.amount1) + if (item.position.amount0?.currency.equals(amountToken0.currency)) + amountToken0 = amountToken0.add(item.position.amount0) + if (item.position.amount1?.currency.equals(amountToken1.currency)) + amountToken1 = amountToken1.add(item.position.amount1) }) const canUnstake = stakedPos.length > 0 @@ -131,7 +134,10 @@ function FarmCard({ const userTotalRewards = farm.totalRewards.map((item, index) => { return stakedPos .map(item => item.unclaimedRewards[index]) - .reduce((total, cur) => total.add(cur), CurrencyAmount.fromRawAmount(item.currency, 0)) + .reduce( + (total, cur) => (cur?.currency?.equals(total.currency) ? total.add(cur) : total), + CurrencyAmount.fromRawAmount(item.currency, 0), + ) }) const myDepositUSD = stakedPos.reduce((total, item) => item.stakedUsdValue + total, 0) diff --git a/src/pages/Farm/ElasticFarmv2/components/ListView.tsx b/src/pages/Farm/ElasticFarmv2/components/ListView.tsx index 6901f83183..a4058de4cc 100644 --- a/src/pages/Farm/ElasticFarmv2/components/ListView.tsx +++ b/src/pages/Farm/ElasticFarmv2/components/ListView.tsx @@ -73,8 +73,10 @@ export const ListView = ({ let amountToken1 = CurrencyAmount.fromRawAmount(farm.token1.wrapped, 0) stakedPos.forEach(item => { - amountToken0 = amountToken0.add(item.position.amount0) - amountToken1 = amountToken1.add(item.position.amount1) + if (item.position.amount0?.currency.equals(amountToken0.currency)) + amountToken0 = amountToken0.add(item.position.amount0) + if (item.position.amount1?.currency.equals(amountToken1.currency)) + amountToken1 = amountToken1.add(item.position.amount1) }) const canUnstake = stakedPos.length > 0 @@ -84,7 +86,10 @@ export const ListView = ({ const userTotalRewards = farm.totalRewards.map((item, index) => { return stakedPos .map(item => item.unclaimedRewards[index]) - .reduce((total, cur) => total.add(cur), CurrencyAmount.fromRawAmount(item.currency, 0)) + .reduce( + (total, cur) => (cur?.currency?.equals(total.currency) ? total.add(cur) : total), + CurrencyAmount.fromRawAmount(item.currency, 0), + ) }) const myDepositUSD = stakedPos.reduce((total, item) => item.stakedUsdValue + total, 0) diff --git a/src/pages/MyEarnings/ElasticPools/SinglePosition/EarningView.tsx b/src/pages/MyEarnings/ElasticPools/SinglePosition/EarningView.tsx index cd88e3c3e2..f1c6e02127 100644 --- a/src/pages/MyEarnings/ElasticPools/SinglePosition/EarningView.tsx +++ b/src/pages/MyEarnings/ElasticPools/SinglePosition/EarningView.tsx @@ -3,7 +3,6 @@ import { useMemo } from 'react' import { Flex, Text } from 'rebass' import styled from 'styled-components' -import { useGetNativeTokenLogo } from 'components/CurrencyLogo' import Logo from 'components/Logo' import { MouseoverTooltip } from 'components/Tooltip' import CommonView, { CommonProps } from 'pages/MyEarnings/ElasticPools/SinglePosition/CommonView' @@ -13,6 +12,7 @@ import OriginalMyEarningsOverTimePanel from 'pages/MyEarnings/MyEarningsOverTime import { calculateEarningStatsTick } from 'pages/MyEarnings/utils' import { useAppSelector } from 'state/hooks' import { EarningStatsTick } from 'types/myEarnings' +import { getNativeTokenLogo } from 'utils' import { formatDisplayNumber } from 'utils/numbers' const MyEarningsOverTimePanel = styled(OriginalMyEarningsOverTimePanel)` @@ -24,7 +24,7 @@ const MyEarningsOverTimePanel = styled(OriginalMyEarningsOverTimePanel)` const EarningView: React.FC = props => { const { positionEarning, chainId } = props const tokensByChainId = useAppSelector(state => state.lists.mapWhitelistTokens) - const nativeLogo = useGetNativeTokenLogo(chainId) + const nativeLogo = getNativeTokenLogo(chainId) // format pool value const ticks: EarningStatsTick[] | undefined = useMemo(() => { diff --git a/src/pages/MyEarnings/PoolEarningsSection.tsx b/src/pages/MyEarnings/PoolEarningsSection.tsx index b6cedb52da..6d0f313dea 100644 --- a/src/pages/MyEarnings/PoolEarningsSection.tsx +++ b/src/pages/MyEarnings/PoolEarningsSection.tsx @@ -6,7 +6,6 @@ import { Box, Flex } from 'rebass' import { HistoricalSingleData } from 'services/earning/types' import styled from 'styled-components' -import { useGetNativeTokenLogo } from 'components/CurrencyLogo' import { NativeCurrencies } from 'constants/tokens' import { fetchListTokenByAddresses } from 'hooks/Tokens' import useTheme from 'hooks/useTheme' @@ -15,7 +14,7 @@ import { useAppSelector } from 'state/hooks' import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo' import { MEDIA_WIDTHS } from 'theme' import { EarningStatsTick, EarningsBreakdown } from 'types/myEarnings' -import { isAddressString } from 'utils' +import { getNativeTokenLogo, isAddressString } from 'utils' import { toString } from 'utils/numbers' import OriginalEarningsBreakdownPanel from './EarningsBreakdownPanel' @@ -89,7 +88,7 @@ const PoolEarningsSection: React.FC = ({ historicalEarning, chainId }) => const theme = useTheme() const upToExtraSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToExtraSmall}px)`) const tokensByChainId = useAppSelector(state => state.lists.mapWhitelistTokens) - const nativeLogo = useGetNativeTokenLogo(chainId) + const nativeLogo = getNativeTokenLogo(chainId) const [tokens, setTokens] = useState<{ [address: string]: WrappedTokenInfo }>({}) diff --git a/src/pages/SwapV3/Tabs/index.tsx b/src/pages/SwapV3/Tabs/index.tsx index dd114da309..a2f2f52f39 100644 --- a/src/pages/SwapV3/Tabs/index.tsx +++ b/src/pages/SwapV3/Tabs/index.tsx @@ -59,7 +59,7 @@ export const Tab = styled(ButtonEmpty)<{ isActive: boolean }>` margin-right: 0; } - ${({ theme }) => theme.mediaWidth.upToSmall` + ${({ theme }) => theme.mediaWidth.upToSmall` padding: 0px 0.75rem; `} ` @@ -104,7 +104,7 @@ export default function Tabs({ activeTab }: Props) { {isSupportLimitOrder(chainId) && onClickTab(TAB.LIMIT)} />} {CHAINS_SUPPORT_CROSS_CHAIN.includes(chainId) && ( - onClickTab(TAB.CROSS_CHAIN)} isActive={isCrossChainPage}> + onClickTab(TAB.CROSS_CHAIN)} isActive={isCrossChainPage} data-testid="cross-chain-tab"> Cross-Chain diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts index 9b5b595417..1aebcef093 100644 --- a/src/react-app-env.d.ts +++ b/src/react-app-env.d.ts @@ -47,13 +47,3 @@ interface Window { recaptchaOptions?: any zESettings?: any } - -declare module 'content-hash' { - function decode(x: string): string - function getCodec(x: string): string -} - -declare module 'multihashes' { - function decode(buff: Uint8Array): { code: number; name: string; length: number; digest: Uint8Array } - function toB58String(hash: Uint8Array): string -} diff --git a/src/state/user/hooks.tsx b/src/state/user/hooks.tsx index 456cc28251..f231cdaa48 100644 --- a/src/state/user/hooks.tsx +++ b/src/state/user/hooks.tsx @@ -101,14 +101,12 @@ export function useUserLocaleManager(): [SupportedLocale | null, (newLocale: Sup return [locale, setLocale] } -// unused for now, but may be added again in the future. So we should keep it here. export function useIsAcceptedTerm(): [boolean, (isAcceptedTerm: boolean) => void] { const dispatch = useAppDispatch() const acceptedTermVersion = useSelector( state => state.user.acceptedTermVersion, ) - // eslint-disable-next-line @typescript-eslint/no-unused-vars const isAcceptedTerm = !!acceptedTermVersion && acceptedTermVersion === TERM_FILES_PATH.VERSION const setIsAcceptedTerm = useCallback( @@ -118,8 +116,7 @@ export function useIsAcceptedTerm(): [boolean, (isAcceptedTerm: boolean) => void [dispatch], ) - // return [isAcceptedTerm, setIsAcceptedTerm] - return [true, setIsAcceptedTerm] + return [isAcceptedTerm, setIsAcceptedTerm] } export function useDegenModeManager(): [boolean, () => void] { @@ -362,7 +359,9 @@ export function useToggleTopTrendingTokens(): () => void { return useCallback(() => dispatch(toggleTopTrendingTokens()), [dispatch]) } -export const useUserFavoriteTokens = (chainId: ChainId) => { +export const useUserFavoriteTokens = (customChain?: ChainId) => { + const { chainId: currentChain } = useActiveWeb3React() + const chainId = customChain || currentChain const dispatch = useDispatch() const { favoriteTokensByChainIdv2: favoriteTokensByChainId } = useSelector((state: AppState) => state.user) const { commonTokens } = useKyberSwapConfig(chainId) diff --git a/src/utils/contenthashToUri.ts b/src/utils/contenthashToUri.ts deleted file mode 100644 index cc516621af..0000000000 --- a/src/utils/contenthashToUri.ts +++ /dev/null @@ -1,43 +0,0 @@ -import CID from 'cids' -import { getCodec, rmPrefix } from 'multicodec' -import { decode, toB58String } from 'multihashes' - -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') - const arr = new Uint8Array(hex.length / 2) - for (let i = 0; i < arr.length; i++) { - arr[i] = parseInt(hex.substr(i * 2, 2), 16) - } - return arr -} - -const UTF_8_DECODER = new TextDecoder() - -/** - * Returns the URI representation of the content hash for supported codecs - * @param contenthash to decode - */ -export default function contenthashToUri(contenthash: string): string { - const buff = hexToUint8Array(contenthash) - const codec = getCodec(buff as Buffer) // the typing is wrong for @types/multicodec - switch (codec) { - case 'ipfs-ns': { - const data = rmPrefix(buff as Buffer) - const cid = new CID(data) - return `ipfs://${toB58String(cid.multihash)}` - } - case 'ipns-ns': { - const data = rmPrefix(buff as Buffer) - const cid = new CID(data) - const multihash = decode(cid.multihash) - if (multihash.name === 'identity') { - return `ipns://${UTF_8_DECODER.decode(multihash.digest).trim()}` - } else { - return `ipns://${toB58String(cid.multihash)}` - } - } - default: - throw new Error(`Unrecognized codec: ${codec}`) - } -} diff --git a/src/utils/index.ts b/src/utils/index.ts index b64d743c33..5edd8718db 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -10,7 +10,7 @@ import blockServiceApi from 'services/blockService' import { GET_BLOCKS } from 'apollo/queries' import { ENV_KEY } from 'constants/env' -import { DEFAULT_GAS_LIMIT_MARGIN, ZERO_ADDRESS } from 'constants/index' +import { DEFAULT_GAS_LIMIT_MARGIN, ETHER_ADDRESS, ZERO_ADDRESS } from 'constants/index' import { NETWORKS_INFO, SUPPORTED_NETWORKS, isEVM } from 'constants/networks' import { KNCL_ADDRESS, KNC_ADDRESS } from 'constants/tokens' import { @@ -387,6 +387,13 @@ export const get24hValue = (valueNow: string, value24HoursAgo: string | undefine return currentChange } +export const getNativeTokenLogo = (chainId: ChainId) => { + return ( + store.getState()?.lists?.mapWhitelistTokens?.[chainId]?.[ETHER_ADDRESS]?.logoURI || + (chainId ? NETWORKS_INFO[chainId].nativeToken.logo : '') + ) +} + export const getTokenLogoURL = (inputAddress: string, chainId: ChainId): string => { let address = inputAddress if (address === ZERO_ADDRESS) { diff --git a/src/utils/parseENSAddress.ts b/src/utils/parseENSAddress.ts deleted file mode 100644 index 68818595fc..0000000000 --- a/src/utils/parseENSAddress.ts +++ /dev/null @@ -1,7 +0,0 @@ -const ENS_NAME_REGEX = /^(([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+)eth(\/.*)?$/ - -export function parseENSAddress(ensAddress: string): { ensName: string; ensPath: string | undefined } | undefined { - const match = ensAddress.match(ENS_NAME_REGEX) - if (!match) return undefined - return { ensName: `${match[1].toLowerCase()}eth`, ensPath: match[4] } -} diff --git a/yarn.lock b/yarn.lock index 1dec1b3ade..7820fb800e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2606,11 +2606,6 @@ "@motionone/dom" "^10.16.2" tslib "^2.3.1" -"@multiformats/base-x@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@multiformats/base-x/-/base-x-4.0.1.tgz#95ff0fa58711789d53aefb2590a8b7a4e715d121" - integrity sha512-eMk0b9ReBbV23xXU693TAIrLyeO5iTgBZGSJfpqriG8UkYvr/hC9u9pyMlAakDNHWmbhMZCDs6KQO0jzKD8OTw== - "@ngraveio/bc-ur@^1.0.0", "@ngraveio/bc-ur@^1.1.5": version "1.1.6" resolved "https://registry.yarnpkg.com/@ngraveio/bc-ur/-/bc-ur-1.1.6.tgz#8f8c75fff22f6a5e4dfbc5a6b540d7fe8f42cd39" @@ -4749,13 +4744,6 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== -"@types/multicodec@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/multicodec/-/multicodec-1.0.0.tgz#9c9c2df84ea5006c65a048873600f71c4565a397" - integrity sha512-UZkJT3rb8AfT2S1bTk7Gj+1wP9GJQ4zSnHDycRxEiI4yPOn47s5rSK86w/EFHvnNBhsu3zl+XNbTnBcxBd9dAQ== - dependencies: - "@types/node" "*" - "@types/node-fetch@^2.6.2": version "2.6.2" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" @@ -5923,11 +5911,6 @@ resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== -"@zxing/text-encoding@0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b" - integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA== - JSONStream@^1.0.4, JSONStream@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -7272,16 +7255,6 @@ ci-info@^3.2.0, ci-info@^3.7.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== -cids@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/cids/-/cids-1.1.9.tgz#402c26db5c07059377bcd6fb82f2a24e7f2f4a4f" - integrity sha512-l11hWRfugIcbGuTZwAM5PwpjPPjyb6UZOGwlHSnOBV5o07XhQ4gNpBN67FbODvpjyHtd+0Xs6KNvUcGBiDRsdg== - dependencies: - multibase "^4.0.1" - multicodec "^3.0.1" - multihashes "^4.0.1" - uint8arrays "^3.0.0" - cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -12947,21 +12920,6 @@ ms@2.1.3, ms@^2.0.0, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -multibase@^3.0.0, multibase@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-3.1.2.tgz#59314e1e2c35d018db38e4c20bb79026827f0f2f" - integrity sha512-bpklWHs70LO3smJUHOjcnzGceJJvn9ui0Vau6Za0B/GBepaXswmW8Ufea0uD9pROf/qCQ4N4lZ3sf3U+SNf0tw== - dependencies: - "@multiformats/base-x" "^4.0.1" - web-encoding "^1.0.6" - -multibase@^4.0.1: - version "4.0.6" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-4.0.6.tgz#6e624341483d6123ca1ede956208cb821b440559" - integrity sha512-x23pDe5+svdLz/k5JPGCVdfn7Q5mZVMBETiC+ORfO+sor9Sgs0smJzAjfTbM5tckeCqnaUuMYoz+k3RXMmJClQ== - dependencies: - "@multiformats/base-x" "^4.0.1" - multicast-dns@^7.2.5: version "7.2.5" resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" @@ -12970,45 +12928,11 @@ multicast-dns@^7.2.5: dns-packet "^5.2.2" thunky "^1.0.2" -multicodec@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-2.1.3.tgz#b9850635ad4e2a285a933151b55b4a2294152a5d" - integrity sha512-0tOH2Gtio39uO41o+2xl9UhRkCWxU5ZmZSbFCh/OjGzkWJI8e6lkN/s4Mj1YfyWoBod+2+S3W+6wO6nhkwN8pA== - dependencies: - uint8arrays "1.1.0" - varint "^6.0.0" - -multicodec@^3.0.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-3.2.1.tgz#82de3254a0fb163a107c1aab324f2a91ef51efb2" - integrity sha512-+expTPftro8VAW8kfvcuNNNBgb9gPeNYV9dn+z1kJRWF2vih+/S79f2RVeIwmrJBUJ6NT9IUPWnZDQvegEh5pw== - dependencies: - uint8arrays "^3.0.0" - varint "^6.0.0" - multiformats@^9.4.2: version "9.9.0" resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37" integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg== -multihashes@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-3.1.2.tgz#ffa5e50497aceb7911f7b4a3b6cada9b9730edfc" - integrity sha512-AP4IoV/YzkNrfbQKZE3OMPibrmy350OmCd6cJkwyM8oExaXIlOY4UnOOVSQtAEuq/LR01XfXKCESidzZvSwHCQ== - dependencies: - multibase "^3.1.0" - uint8arrays "^2.0.5" - varint "^6.0.0" - -multihashes@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-4.0.3.tgz#426610539cd2551edbf533adeac4c06b3b90fb05" - integrity sha512-0AhMH7Iu95XjDLxIeuCOOE4t9+vQZsACyKZ9Fxw2pcsRmlX4iCn1mby0hS0bb+nQOVpdQYWPpnyusw4da5RPhA== - dependencies: - multibase "^4.0.1" - uint8arrays "^3.0.0" - varint "^5.0.2" - mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -17038,14 +16962,6 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== -uint8arrays@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-1.1.0.tgz#d034aa65399a9fd213a1579e323f0b29f67d0ed2" - integrity sha512-cLdlZ6jnFczsKf5IH1gPHTtcHtPGho5r4CvctohmQjw8K7Q3gFdfIGHxSTdTaCKrL4w09SsPRJTqRS0drYeszA== - dependencies: - multibase "^3.0.0" - web-encoding "^1.0.2" - uint8arrays@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.0.tgz#8186b8eafce68f28bd29bd29d683a311778901e2" @@ -17053,13 +16969,6 @@ uint8arrays@3.1.0: dependencies: multiformats "^9.4.2" -uint8arrays@^2.0.5: - version "2.1.10" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-2.1.10.tgz#34d023c843a327c676e48576295ca373c56e286a" - integrity sha512-Q9/hhJa2836nQfEJSZTmr+pg9+cDJS9XEAp7N2Vg5MzL3bK/mkMVfjscRGYruP9jNda6MAdf4QD/y78gSzkp6A== - dependencies: - multiformats "^9.4.2" - uint8arrays@^3.0.0, uint8arrays@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.1.tgz#2d8762acce159ccd9936057572dade9459f65ae0" @@ -17275,7 +17184,7 @@ util.promisify@1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" -util@^0.12.0, util@^0.12.3, util@^0.12.4, util@^0.12.5: +util@^0.12.0, util@^0.12.4, util@^0.12.5: version "0.12.5" resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== @@ -17329,16 +17238,6 @@ valtio@1.10.5: proxy-compare "2.5.1" use-sync-external-store "1.2.0" -varint@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" - integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== - -varint@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/varint/-/varint-6.0.0.tgz#9881eb0ce8feaea6512439d19ddf84bf551661d0" - integrity sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg== - vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -17550,15 +17449,6 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -web-encoding@^1.0.2, web-encoding@^1.0.6: - version "1.1.5" - resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864" - integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA== - dependencies: - util "^0.12.3" - optionalDependencies: - "@zxing/text-encoding" "0.9.0" - web-streams-polyfill@^3.0.3: version "3.2.1" resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"