Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5979635939 | ||
|
|
5399bdb550 | ||
|
|
1df9da9eff | ||
|
|
b1e6d0ab7a | ||
|
|
a7fcbb4cfc | ||
|
|
a5a6a037e5 | ||
|
|
8bfebd37a2 | ||
|
|
4029819090 | ||
|
|
021ae5e74e | ||
|
|
2b9720705f | ||
|
|
8f1ea32e5e | ||
|
|
23acb3b395 | ||
|
|
772416cc7a | ||
|
|
f15e5725f1 | ||
|
|
83c8393f19 | ||
|
|
1348eb3322 | ||
|
|
a2271ba428 | ||
|
|
1845cb3b7b | ||
|
|
6a02bde8e0 | ||
|
|
c18522159b | ||
|
|
5ea7b1de3f | ||
|
|
6efe8f3260 | ||
|
|
9ac28a4571 | ||
|
|
bde1421ffb | ||
|
|
3dceb45d9e | ||
|
|
7b589561bc |
2
.env
2
.env
@@ -1,5 +1,6 @@
|
||||
# These API keys are intentionally public. Please do not report them - thank you for your concern.
|
||||
REACT_APP_AMPLITUDE_PROXY_URL="https://api.uniswap.org/v1/amplitude-proxy"
|
||||
REACT_APP_STATSIG_PROXY_URL="https://api.uniswap.org/v1/statsig-proxy"
|
||||
REACT_APP_AWS_API_REGION="us-east-2"
|
||||
REACT_APP_AWS_API_ENDPOINT="https://beta.api.uniswap.org/v1/graphql"
|
||||
REACT_APP_TEMP_API_URL="https://temp.api.uniswap.org/v1"
|
||||
@@ -10,4 +11,3 @@ REACT_APP_INFURA_KEY="4bf032f2d38a4ed6bb975b80d6340847"
|
||||
REACT_APP_MOONPAY_API="https://api.moonpay.com"
|
||||
REACT_APP_MOONPAY_LINK="https://us-central1-uniswap-mobile.cloudfunctions.net/signMoonpayLinkStaging?platform=web"
|
||||
REACT_APP_MOONPAY_PUBLISHABLE_KEY="pk_test_DycfESRid31UaSxhI5yWKe1r5E5kKSz"
|
||||
REACT_APP_STATSIG_API_KEY="client-1rY92WZGidd2hgW4x1lsZ7afqm1Qfr3sJfH3A5b8eJa"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# These API keys are intentionally public. Please do not report them - thank you for your concern.
|
||||
REACT_APP_AMPLITUDE_PROXY_URL="https://api.uniswap.org/v1/amplitude-proxy"
|
||||
REACT_APP_STATSIG_PROXY_URL="https://api.uniswap.org/v1/statsig-proxy"
|
||||
REACT_APP_AWS_API_ENDPOINT="https://api.uniswap.org/v1/graphql"
|
||||
REACT_APP_FORTMATIC_KEY="pk_live_F937DF033A1666BF"
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID="G-KDP9B6W4H8"
|
||||
@@ -9,4 +11,3 @@ REACT_APP_MOONPAY_PUBLISHABLE_KEY="pk_live_uQG4BJC4w3cxnqpcSqAfohdBFDTsY6E"
|
||||
REACT_APP_FIREBASE_KEY="AIzaSyBcZWwTcTJHj_R6ipZcrJkXdq05PuX0Rs0"
|
||||
THE_GRAPH_SCHEMA_ENDPOINT="https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3"
|
||||
REACT_APP_SENTRY_ENABLED=false
|
||||
REACT_APP_STATSIG_API_KEY="client-1rY92WZGidd2hgW4x1lsZ7afqm1Qfr3sJfH3A5b8eJa"
|
||||
|
||||
4
.github/workflows/release.yaml
vendored
4
.github/workflows/release.yaml
vendored
@@ -62,7 +62,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
timeout-minutes: 2
|
||||
with:
|
||||
cid: ${{ steps.upload.outputs.hash }}
|
||||
cid: ${{ steps.pinata.outputs.hash }}
|
||||
seeds: ${{ secrets.CRUST_SEEDS }}
|
||||
|
||||
- name: Convert CIDv0 to CIDv1
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
IPFS gateways:
|
||||
- https://${{ steps.convert-cidv0.outputs.cidv1 }}.ipfs.dweb.link/
|
||||
- https://${{ steps.convert-cidv0.outputs.cidv1 }}.ipfs.cf-ipfs.com/
|
||||
- [ipfs://${{ steps.upload.outputs.hash }}/](ipfs://${{ steps.pinata.outputs.hash }}/)
|
||||
- [ipfs://${{ steps.pinata.outputs.hash }}/](ipfs://${{ steps.pinata.outputs.hash }}/)
|
||||
|
||||
${{ needs.tag.outputs.changelog }}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.7.2",
|
||||
"@coinbase/wallet-sdk": "^3.3.0",
|
||||
"@coinbase/wallet-sdk": "^3.6.4",
|
||||
"@fontsource/ibm-plex-mono": "^4.5.1",
|
||||
"@fontsource/inter": "^4.5.1",
|
||||
"@graphql-codegen/cli": "^2.15.0",
|
||||
@@ -133,8 +133,8 @@
|
||||
"@reduxjs/toolkit": "^1.6.1",
|
||||
"@sentry/react": "^7.29.0",
|
||||
"@types/react-window-infinite-loader": "^1.0.6",
|
||||
"@uniswap/analytics": "^1.3.0",
|
||||
"@uniswap/analytics-events": "^2.3.0",
|
||||
"@uniswap/analytics": "^1.3.1",
|
||||
"@uniswap/analytics-events": "^2.4.0",
|
||||
"@uniswap/conedison": "^1.3.0",
|
||||
"@uniswap/governance": "^1.0.2",
|
||||
"@uniswap/liquidity-staker": "^1.0.2",
|
||||
@@ -152,7 +152,7 @@
|
||||
"@uniswap/v3-core": "1.0.0",
|
||||
"@uniswap/v3-periphery": "^1.1.1",
|
||||
"@uniswap/v3-sdk": "^3.9.0",
|
||||
"@uniswap/widgets": "^2.29.3",
|
||||
"@uniswap/widgets": "^2.40.0",
|
||||
"@vanilla-extract/css": "^1.7.2",
|
||||
"@vanilla-extract/css-utils": "^0.1.2",
|
||||
"@vanilla-extract/dynamic": "^2.0.2",
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import * as Sentry from '@sentry/react'
|
||||
import { sendAnalyticsEvent } from '@uniswap/analytics'
|
||||
import { SwapEventName } from '@uniswap/analytics-events'
|
||||
import { ButtonLight, SmallButtonPrimary } from 'components/Button'
|
||||
import { ChevronUpIcon } from 'nft/components/icons'
|
||||
import { useIsMobile } from 'nft/hooks'
|
||||
import React, { PropsWithChildren, useState } from 'react'
|
||||
import { Copy } from 'react-feather'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import styled from 'styled-components/macro'
|
||||
import { isSentryEnabled } from 'utils/env'
|
||||
|
||||
@@ -217,13 +220,19 @@ const updateServiceWorkerInBackground = async () => {
|
||||
}
|
||||
|
||||
export default function ErrorBoundary({ children }: PropsWithChildren): JSX.Element {
|
||||
const { pathname } = useLocation()
|
||||
return (
|
||||
<Sentry.ErrorBoundary
|
||||
fallback={({ error, eventId }) => <Fallback error={error} eventId={eventId} />}
|
||||
beforeCapture={(scope) => {
|
||||
scope.setLevel('fatal')
|
||||
}}
|
||||
onError={updateServiceWorkerInBackground}
|
||||
onError={(error) => {
|
||||
updateServiceWorkerInBackground()
|
||||
if (pathname === '/swap') {
|
||||
sendAnalyticsEvent(SwapEventName.SWAP_ERROR, { error })
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Sentry.ErrorBoundary>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'featureFlags'
|
||||
import { GqlRoutingVariant, useGqlRoutingFlag } from 'featureFlags/flags/gqlRouting'
|
||||
import { NftListV2Variant, useNftListV2Flag } from 'featureFlags/flags/nftListV2'
|
||||
import { PayWithAnyTokenVariant, usePayWithAnyTokenFlag } from 'featureFlags/flags/payWithAnyToken'
|
||||
import { Permit2Variant, usePermit2Flag } from 'featureFlags/flags/permit2'
|
||||
import { SwapWidgetVariant, useSwapWidgetFlag } from 'featureFlags/flags/swapWidget'
|
||||
@@ -212,12 +211,6 @@ export default function FeatureFlagModal() {
|
||||
featureFlag={FeatureFlag.permit2}
|
||||
label="Permit 2 / Universal Router"
|
||||
/>
|
||||
<FeatureFlagOption
|
||||
variant={NftListV2Variant}
|
||||
value={useNftListV2Flag()}
|
||||
featureFlag={FeatureFlag.nftListV2}
|
||||
label="NFT Listing Page v2"
|
||||
/>
|
||||
<FeatureFlagOption
|
||||
variant={PayWithAnyTokenVariant}
|
||||
value={usePayWithAnyTokenFlag()}
|
||||
|
||||
@@ -10,8 +10,10 @@ import { CustomLightSpinner, ThemedText } from 'theme'
|
||||
import Circle from '../../assets/images/blue-loader.svg'
|
||||
import Modal from '../Modal'
|
||||
|
||||
const Wrapper = styled.div`
|
||||
background-color: ${({ theme }) => theme.white};
|
||||
const MOONPAY_DARK_BACKGROUND = '#1c1c1e'
|
||||
const Wrapper = styled.div<{ isDarkMode: boolean }>`
|
||||
// #1c1c1e is the background color for the darkmode moonpay iframe as of 2/16/2023
|
||||
background-color: ${({ isDarkMode, theme }) => (isDarkMode ? MOONPAY_DARK_BACKGROUND : theme.white)};
|
||||
border-radius: 20px;
|
||||
box-shadow: ${({ theme }) => theme.deepShadow};
|
||||
display: flex;
|
||||
@@ -29,8 +31,9 @@ const ErrorText = styled(ThemedText.BodyPrimary)`
|
||||
text-align: center;
|
||||
width: 90%;
|
||||
`
|
||||
const StyledIframe = styled.iframe`
|
||||
background-color: ${({ theme }) => theme.white};
|
||||
const StyledIframe = styled.iframe<{ isDarkMode: boolean }>`
|
||||
// #1c1c1e is the background color for the darkmode moonpay iframe as of 2/16/2023
|
||||
background-color: ${({ isDarkMode, theme }) => (isDarkMode ? MOONPAY_DARK_BACKGROUND : theme.white)};
|
||||
border-radius: 12px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@@ -123,7 +126,7 @@ export default function FiatOnrampModal() {
|
||||
|
||||
return (
|
||||
<Modal isOpen={fiatOnrampModalOpen} onDismiss={closeModal} maxHeight={720}>
|
||||
<Wrapper data-testid="fiat-onramp-modal">
|
||||
<Wrapper data-testid="fiat-onramp-modal" isDarkMode={isDarkMode}>
|
||||
{error ? (
|
||||
<>
|
||||
<ThemedText.MediumHeader>
|
||||
@@ -138,7 +141,12 @@ export default function FiatOnrampModal() {
|
||||
) : loading ? (
|
||||
<StyledSpinner src={Circle} alt="loading spinner" size="90px" />
|
||||
) : (
|
||||
<StyledIframe src={signedIframeUrl ?? ''} frameBorder="0" title="fiat-onramp-iframe" />
|
||||
<StyledIframe
|
||||
src={signedIframeUrl ?? ''}
|
||||
frameBorder="0"
|
||||
title="fiat-onramp-iframe"
|
||||
isDarkMode={isDarkMode}
|
||||
/>
|
||||
)}
|
||||
</Wrapper>
|
||||
</Modal>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import Web3Status from 'components/Web3Status'
|
||||
import { NftListV2Variant, useNftListV2Flag } from 'featureFlags/flags/nftListV2'
|
||||
import { chainIdToBackendName } from 'graphql/data/util'
|
||||
import { useIsNftPage } from 'hooks/useIsNftPage'
|
||||
import { Box } from 'nft/components/Box'
|
||||
@@ -82,7 +81,6 @@ export const PageTabs = () => {
|
||||
const Navbar = () => {
|
||||
const isNftPage = useIsNftPage()
|
||||
const sellPageState = useProfilePageState((state) => state.state)
|
||||
const isNftListV2 = useNftListV2Flag() === NftListV2Variant.Enabled
|
||||
const navigate = useNavigate()
|
||||
|
||||
return (
|
||||
@@ -124,7 +122,7 @@ const Navbar = () => {
|
||||
<Box display={{ sm: 'none', lg: 'flex' }}>
|
||||
<MenuDropdown />
|
||||
</Box>
|
||||
{isNftPage && (!isNftListV2 || sellPageState !== ProfilePageStateType.LISTING) && <Bag />}
|
||||
{isNftPage && sellPageState !== ProfilePageStateType.LISTING && <Bag />}
|
||||
{!isNftPage && (
|
||||
<Box display={{ sm: 'none', lg: 'flex' }}>
|
||||
<ChainSelector />
|
||||
|
||||
@@ -105,7 +105,7 @@ exports[`renders currency rows correctly when currencies list is non-empty 1`] =
|
||||
}
|
||||
|
||||
<div
|
||||
style="padding-right: 8px; padding-top: 8px;"
|
||||
style="padding-right: 4px;"
|
||||
>
|
||||
<div
|
||||
class="CurrencyList_scrollbarStyle__1pi21y70"
|
||||
@@ -388,7 +388,7 @@ exports[`renders loading rows when isLoading is true 1`] = `
|
||||
}
|
||||
|
||||
<div
|
||||
style="padding-right: 8px; padding-top: 8px;"
|
||||
style="padding-right: 4px;"
|
||||
>
|
||||
<div
|
||||
class="CurrencyList_scrollbarStyle__1pi21y70"
|
||||
|
||||
@@ -290,7 +290,7 @@ export default function CurrencyList({
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div style={{ paddingRight: '8px', paddingTop: '8px' }}>
|
||||
<div style={{ paddingRight: '4px' }}>
|
||||
{isLoading ? (
|
||||
<FixedSizeList
|
||||
className={styles.scrollbarStyle}
|
||||
|
||||
@@ -3,11 +3,10 @@ import { formatCurrencyAmount, NumberType } from '@uniswap/conedison/format'
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { NATIVE_CHAIN_ID } from 'constants/tokens'
|
||||
import { FeatureGate } from 'featureFlags/flags/featureFlags'
|
||||
import { useDummyGateEnabled } from 'featureFlags/flags/dummyFeatureGate'
|
||||
import { CHAIN_ID_TO_BACKEND_NAME } from 'graphql/data/util'
|
||||
import { useStablecoinValue } from 'hooks/useStablecoinPrice'
|
||||
import useCurrencyBalance from 'lib/hooks/useCurrencyBalance'
|
||||
import { useGate } from 'statsig-react'
|
||||
import styled from 'styled-components/macro'
|
||||
import { StyledInternalLink } from 'theme'
|
||||
|
||||
@@ -89,7 +88,7 @@ export default function MobileBalanceSummaryFooter({ token }: { token: Currency
|
||||
const formattedBalance = formatCurrencyAmount(balance, NumberType.TokenNonTx)
|
||||
const formattedUsdValue = formatCurrencyAmount(useStablecoinValue(balance), NumberType.FiatTokenStats)
|
||||
const chain = CHAIN_ID_TO_BACKEND_NAME[token.chainId].toLowerCase()
|
||||
const { value: isDummyGateFlagEnabled } = useGate(FeatureGate.DUMMY)
|
||||
const isDummyGateFlagEnabled = useDummyGateEnabled()
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
|
||||
@@ -57,7 +57,7 @@ export default function Widget({
|
||||
onDefaultTokenChange,
|
||||
onReviewSwapClick,
|
||||
}: WidgetProps) {
|
||||
const { connector, provider } = useWeb3React()
|
||||
const { connector, provider, chainId } = useWeb3React()
|
||||
const locale = useActiveLocale()
|
||||
const theme = useWidgetTheme()
|
||||
const { inputs, tokenSelector } = useSyncWidgetInputs({
|
||||
@@ -169,7 +169,7 @@ export default function Widget({
|
||||
locale={locale}
|
||||
theme={theme}
|
||||
width={width}
|
||||
// defaultChainId is excluded - it is always inferred from the passed provider
|
||||
defaultChainId={chainId}
|
||||
onConnectWalletClick={onConnectWalletClick}
|
||||
provider={provider}
|
||||
onSwitchChain={onSwitchChain}
|
||||
@@ -183,6 +183,9 @@ export default function Widget({
|
||||
onSwapApprove={onApproveToken}
|
||||
onInitialSwapQuote={onInitialSwapQuote}
|
||||
onSwapPriceUpdateAck={onSwapPriceUpdateAck}
|
||||
onError={(error, errorInfo) => {
|
||||
sendAnalyticsEvent(SwapEventName.SWAP_ERROR, { error, errorInfo, ...trace })
|
||||
}}
|
||||
/>
|
||||
{tokenSelector}
|
||||
</>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { sendAnalyticsEvent, useTrace } from '@uniswap/analytics'
|
||||
import { InterfaceSectionName, SwapEventName } from '@uniswap/analytics-events'
|
||||
import { Currency, Field, SwapController, SwapEventHandlers, TradeType } from '@uniswap/widgets'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import CurrencySearchModal from 'components/SearchModal/CurrencySearchModal'
|
||||
import usePrevious from 'hooks/usePrevious'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
const EMPTY_AMOUNT = ''
|
||||
@@ -29,24 +31,35 @@ export function useSyncWidgetInputs({
|
||||
}) {
|
||||
const trace = useTrace({ section: InterfaceSectionName.WIDGET })
|
||||
|
||||
const { chainId } = useWeb3React()
|
||||
const previousChainId = usePrevious(chainId)
|
||||
|
||||
const [type, setType] = useState<SwapValue['type']>(TradeType.EXACT_INPUT)
|
||||
const [amount, setAmount] = useState<SwapValue['amount']>(EMPTY_AMOUNT)
|
||||
const [tokens, setTokens] = useState<SwapTokens>(defaultTokens)
|
||||
|
||||
useEffect(() => {
|
||||
if (!tokens[Field.INPUT] && !tokens[Field.OUTPUT]) {
|
||||
setTokens((tokens) => {
|
||||
const update = {
|
||||
...tokens,
|
||||
[Field.INPUT]: defaultTokens[Field.INPUT] ?? tokens[Field.INPUT],
|
||||
[Field.OUTPUT]: defaultTokens[Field.OUTPUT] ?? tokens[Field.OUTPUT] ?? defaultTokens.default,
|
||||
default: defaultTokens.default,
|
||||
}
|
||||
return update
|
||||
setTokens({
|
||||
...tokens,
|
||||
[Field.INPUT]: defaultTokens[Field.INPUT] ?? tokens[Field.INPUT],
|
||||
[Field.OUTPUT]: defaultTokens[Field.OUTPUT] ?? tokens[Field.OUTPUT] ?? defaultTokens.default,
|
||||
default: defaultTokens.default,
|
||||
})
|
||||
}
|
||||
}, [defaultTokens, tokens])
|
||||
|
||||
useEffect(() => {
|
||||
if (chainId !== previousChainId && !!previousChainId) {
|
||||
setTokens({
|
||||
...tokens,
|
||||
[Field.INPUT]: undefined,
|
||||
[Field.OUTPUT]: undefined,
|
||||
})
|
||||
setAmount(EMPTY_AMOUNT)
|
||||
}
|
||||
}, [chainId, previousChainId, tokens])
|
||||
|
||||
const onAmountChange = useCallback(
|
||||
(field: Field, amount: string, origin?: 'max') => {
|
||||
if (origin === 'max') {
|
||||
|
||||
@@ -9,8 +9,12 @@ class TokenLogoLookupTable {
|
||||
initialize() {
|
||||
const dict: { [key: string]: string[] | undefined } = {}
|
||||
|
||||
DEFAULT_LIST_OF_LISTS.forEach((list) =>
|
||||
store.getState().lists.byUrl[list].current?.tokens.forEach((token) => {
|
||||
DEFAULT_LIST_OF_LISTS.forEach((list) => {
|
||||
const listData = store.getState().lists.byUrl[list]
|
||||
if (!listData) {
|
||||
return
|
||||
}
|
||||
listData.current?.tokens.forEach((token) => {
|
||||
if (token.logoURI) {
|
||||
const lowercaseAddress = token.address.toLowerCase()
|
||||
const currentEntry = dict[lowercaseAddress + ':' + token.chainId]
|
||||
@@ -21,7 +25,7 @@ class TokenLogoLookupTable {
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
})
|
||||
this.dict = dict
|
||||
this.initialized = true
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const UNI_LIST = 'https://tokens.uniswap.org'
|
||||
export const UNI_EXTENDED_LIST = 'https://extendedtokens.uniswap.org/'
|
||||
const UNI_UNSUPPORTED_LIST = 'https://unsupportedtokens.uniswap.org/'
|
||||
export const UNI_LIST = 'https://gateway.ipfs.io/ipns/tokens.uniswap.org'
|
||||
export const UNI_EXTENDED_LIST = 'https://gateway.ipfs.io/ipns/extendedtokens.uniswap.org'
|
||||
const UNI_UNSUPPORTED_LIST = 'https://gateway.ipfs.io/ipns/unsupportedtokens.uniswap.org'
|
||||
const AAVE_LIST = 'tokenlist.aave.eth'
|
||||
const BA_LIST = 'https://raw.githubusercontent.com/The-Blockchain-Association/sec-notice-list/master/ba-sec-list.json'
|
||||
const CMC_ALL_LIST = 'https://api.coinmarketcap.com/data-api/v3/uniswap/all.json'
|
||||
|
||||
9
src/featureFlags/flags/dummyFeatureGate.ts
Normal file
9
src/featureFlags/flags/dummyFeatureGate.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
|
||||
|
||||
function useDummyGateFlag(): BaseVariant {
|
||||
return useBaseFlag(FeatureFlag.statsigDummy)
|
||||
}
|
||||
|
||||
export function useDummyGateEnabled(): boolean {
|
||||
return useDummyGateFlag() === BaseVariant.Enabled
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
/**
|
||||
* The value here must match the value in the statsig dashboard, if you plan to use statsig.
|
||||
*/
|
||||
export enum FeatureFlag {
|
||||
traceJsonRpc = 'traceJsonRpc',
|
||||
permit2 = 'permit2',
|
||||
nftListV2 = 'nftListV2',
|
||||
payWithAnyToken = 'payWithAnyToken',
|
||||
swapWidget = 'swapWidget',
|
||||
swapWidget = 'swap_widget_replacement_enabled',
|
||||
gqlRouting = 'gqlRouting',
|
||||
}
|
||||
|
||||
export enum FeatureGate {
|
||||
DUMMY = 'web_dummy_gate_amplitude_id',
|
||||
statsigDummy = 'web_dummy_gate_amplitude_id',
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
|
||||
|
||||
export function useGqlRoutingFlag(): BaseVariant {
|
||||
return useBaseFlag(FeatureFlag.gqlRouting)
|
||||
return useBaseFlag(FeatureFlag.gqlRouting, BaseVariant.Enabled)
|
||||
}
|
||||
|
||||
export { BaseVariant as GqlRoutingVariant }
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { BaseVariant } from '../index'
|
||||
|
||||
export function useNftListV2Flag(): BaseVariant {
|
||||
return BaseVariant.Enabled
|
||||
}
|
||||
|
||||
export { BaseVariant as NftListV2Variant }
|
||||
@@ -4,7 +4,7 @@ import { useWeb3React } from '@web3-react/core'
|
||||
import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
|
||||
|
||||
export function usePayWithAnyTokenFlag(): BaseVariant {
|
||||
return useBaseFlag(FeatureFlag.payWithAnyToken)
|
||||
return useBaseFlag(FeatureFlag.payWithAnyToken, BaseVariant.Enabled)
|
||||
}
|
||||
|
||||
export function usePayWithAnyTokenEnabled(): boolean {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { atomWithStorage, useAtomValue, useUpdateAtom } from 'jotai/utils'
|
||||
import { createContext, ReactNode, useCallback, useContext } from 'react'
|
||||
import { useGate } from 'statsig-react'
|
||||
export { FeatureFlag } from './flags/featureFlags'
|
||||
|
||||
interface FeatureFlagsContextType {
|
||||
@@ -56,7 +57,12 @@ export enum BaseVariant {
|
||||
}
|
||||
|
||||
export function useBaseFlag(flag: string, defaultValue = BaseVariant.Control): BaseVariant {
|
||||
switch (useFeatureFlagsContext().flags[flag]) {
|
||||
const { value: statsigValue } = useGate(flag) // non-existent gates return false
|
||||
const featureFlagsContext = useFeatureFlagsContext()
|
||||
if (statsigValue) {
|
||||
return BaseVariant.Enabled
|
||||
}
|
||||
switch (featureFlagsContext.flags[flag]) {
|
||||
case 'enabled':
|
||||
return BaseVariant.Enabled
|
||||
case 'control':
|
||||
|
||||
86
src/graphql/data/__generated__/types-and-hooks.ts
generated
86
src/graphql/data/__generated__/types-and-hooks.ts
generated
@@ -86,6 +86,10 @@ export enum Chain {
|
||||
UnknownChain = 'UNKNOWN_CHAIN'
|
||||
}
|
||||
|
||||
export enum CollectionSortableField {
|
||||
Volume = 'VOLUME'
|
||||
}
|
||||
|
||||
export type ContractInput = {
|
||||
address?: InputMaybe<Scalars['String']>;
|
||||
chain: Chain;
|
||||
@@ -96,11 +100,6 @@ export enum Currency {
|
||||
Usd = 'USD'
|
||||
}
|
||||
|
||||
export enum DatasourceProvider {
|
||||
Alternate = 'ALTERNATE',
|
||||
Legacy = 'LEGACY'
|
||||
}
|
||||
|
||||
export type Dimensions = {
|
||||
__typename?: 'Dimensions';
|
||||
height?: Maybe<Scalars['Float']>;
|
||||
@@ -145,6 +144,49 @@ export enum MarketSortableField {
|
||||
Volume = 'VOLUME'
|
||||
}
|
||||
|
||||
export type NftActivity = {
|
||||
__typename?: 'NftActivity';
|
||||
address: Scalars['String'];
|
||||
asset?: Maybe<NftAsset>;
|
||||
fromAddress: Scalars['String'];
|
||||
id: Scalars['ID'];
|
||||
marketplace?: Maybe<NftMarketplace>;
|
||||
orderStatus?: Maybe<OrderStatus>;
|
||||
price?: Maybe<Amount>;
|
||||
quantity?: Maybe<Scalars['Int']>;
|
||||
timestamp: Scalars['Int'];
|
||||
toAddress?: Maybe<Scalars['String']>;
|
||||
tokenId?: Maybe<Scalars['String']>;
|
||||
transactionHash?: Maybe<Scalars['String']>;
|
||||
type: NftActivityType;
|
||||
url?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type NftActivityConnection = {
|
||||
__typename?: 'NftActivityConnection';
|
||||
edges: Array<NftActivityEdge>;
|
||||
pageInfo: PageInfo;
|
||||
};
|
||||
|
||||
export type NftActivityEdge = {
|
||||
__typename?: 'NftActivityEdge';
|
||||
cursor: Scalars['String'];
|
||||
node: NftActivity;
|
||||
};
|
||||
|
||||
export type NftActivityFilterInput = {
|
||||
activityTypes?: InputMaybe<Array<NftActivityType>>;
|
||||
address?: InputMaybe<Scalars['String']>;
|
||||
tokenId?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export enum NftActivityType {
|
||||
CancelListing = 'CANCEL_LISTING',
|
||||
Listing = 'LISTING',
|
||||
Sale = 'SALE',
|
||||
Transfer = 'TRANSFER'
|
||||
}
|
||||
|
||||
export type NftApproval = {
|
||||
__typename?: 'NftApproval';
|
||||
approvedAddress: Scalars['String'];
|
||||
@@ -196,7 +238,6 @@ export type NftAssetListingsArgs = {
|
||||
after?: InputMaybe<Scalars['String']>;
|
||||
asc?: InputMaybe<Scalars['Boolean']>;
|
||||
before?: InputMaybe<Scalars['String']>;
|
||||
datasource?: InputMaybe<DatasourceProvider>;
|
||||
first?: InputMaybe<Scalars['Int']>;
|
||||
last?: InputMaybe<Scalars['Int']>;
|
||||
};
|
||||
@@ -311,7 +352,6 @@ export type NftCollection = {
|
||||
|
||||
export type NftCollectionMarketsArgs = {
|
||||
currencies: Array<Currency>;
|
||||
datasource?: InputMaybe<DatasourceProvider>;
|
||||
};
|
||||
|
||||
export type NftCollectionConnection = {
|
||||
@@ -335,6 +375,8 @@ export type NftCollectionMarket = {
|
||||
marketplaces?: Maybe<Array<NftCollectionMarketplace>>;
|
||||
nftContracts?: Maybe<Array<NftContract>>;
|
||||
owners?: Maybe<Scalars['Int']>;
|
||||
percentListed?: Maybe<TimestampedAmount>;
|
||||
percentUniqueOwners?: Maybe<TimestampedAmount>;
|
||||
sales?: Maybe<TimestampedAmount>;
|
||||
totalVolume?: Maybe<TimestampedAmount>;
|
||||
volume?: Maybe<TimestampedAmount>;
|
||||
@@ -602,6 +644,7 @@ export type PortfolioTokensTotalDenominatedValueChangeArgs = {
|
||||
|
||||
export type Query = {
|
||||
__typename?: 'Query';
|
||||
nftActivity?: Maybe<NftActivityConnection>;
|
||||
nftAssets?: Maybe<NftAssetConnection>;
|
||||
nftBalances?: Maybe<NftBalanceConnection>;
|
||||
nftCollections?: Maybe<NftCollectionConnection>;
|
||||
@@ -613,17 +656,25 @@ export type Query = {
|
||||
token?: Maybe<Token>;
|
||||
tokenProjects?: Maybe<Array<Maybe<TokenProject>>>;
|
||||
tokens?: Maybe<Array<Maybe<Token>>>;
|
||||
topCollections?: Maybe<NftCollectionConnection>;
|
||||
topTokens?: Maybe<Array<Maybe<Token>>>;
|
||||
};
|
||||
|
||||
|
||||
export type QueryNftActivityArgs = {
|
||||
chain?: InputMaybe<Chain>;
|
||||
cursor?: InputMaybe<Scalars['String']>;
|
||||
filter?: InputMaybe<NftActivityFilterInput>;
|
||||
limit?: InputMaybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
|
||||
export type QueryNftAssetsArgs = {
|
||||
address: Scalars['String'];
|
||||
after?: InputMaybe<Scalars['String']>;
|
||||
asc?: InputMaybe<Scalars['Boolean']>;
|
||||
before?: InputMaybe<Scalars['String']>;
|
||||
chain?: InputMaybe<Chain>;
|
||||
datasource?: InputMaybe<DatasourceProvider>;
|
||||
filter?: InputMaybe<NftAssetsFilterInput>;
|
||||
first?: InputMaybe<Scalars['Int']>;
|
||||
last?: InputMaybe<Scalars['Int']>;
|
||||
@@ -636,7 +687,6 @@ export type QueryNftBalancesArgs = {
|
||||
before?: InputMaybe<Scalars['String']>;
|
||||
chain?: InputMaybe<Chain>;
|
||||
cursor?: InputMaybe<Scalars['String']>;
|
||||
datasource?: InputMaybe<DatasourceProvider>;
|
||||
filter?: InputMaybe<NftBalancesFilterInput>;
|
||||
first?: InputMaybe<Scalars['Int']>;
|
||||
last?: InputMaybe<Scalars['Int']>;
|
||||
@@ -646,12 +696,10 @@ export type QueryNftBalancesArgs = {
|
||||
|
||||
|
||||
export type QueryNftCollectionsArgs = {
|
||||
after?: InputMaybe<Scalars['String']>;
|
||||
before?: InputMaybe<Scalars['String']>;
|
||||
datasource?: InputMaybe<DatasourceProvider>;
|
||||
chain?: InputMaybe<Chain>;
|
||||
cursor?: InputMaybe<Scalars['String']>;
|
||||
filter?: InputMaybe<NftCollectionsFilterInput>;
|
||||
first?: InputMaybe<Scalars['Int']>;
|
||||
last?: InputMaybe<Scalars['Int']>;
|
||||
limit?: InputMaybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
|
||||
@@ -670,7 +718,6 @@ export type QueryNftRouteArgs = {
|
||||
|
||||
export type QueryPortfoliosArgs = {
|
||||
ownerAddresses: Array<Scalars['String']>;
|
||||
useAltDataSource?: InputMaybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
|
||||
@@ -700,6 +747,15 @@ export type QueryTokensArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type QueryTopCollectionsArgs = {
|
||||
chains?: InputMaybe<Array<Chain>>;
|
||||
cursor?: InputMaybe<Scalars['String']>;
|
||||
duration?: InputMaybe<HistoryDuration>;
|
||||
limit?: InputMaybe<Scalars['Int']>;
|
||||
orderBy?: InputMaybe<CollectionSortableField>;
|
||||
};
|
||||
|
||||
|
||||
export type QueryTopTokensArgs = {
|
||||
chain?: InputMaybe<Chain>;
|
||||
orderBy?: InputMaybe<TokenSortableField>;
|
||||
|
||||
@@ -112,7 +112,7 @@ export function useSearchInactiveTokenLists(search: string | undefined, minResul
|
||||
const result: WrappedTokenInfo[] = []
|
||||
const addressSet: { [address: string]: true } = {}
|
||||
for (const url of inactiveUrls) {
|
||||
const list = lists[url].current
|
||||
const list = lists[url]?.current
|
||||
if (!list) continue
|
||||
for (const tokenInfo of list.tokens) {
|
||||
if (tokenInfo.chainId === chainId && tokenFilter(tokenInfo)) {
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { sendAnalyticsEvent } from '@uniswap/analytics'
|
||||
import { NFTEventName } from '@uniswap/analytics-events'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { GqlRoutingVariant, useGqlRoutingFlag } from 'featureFlags/flags/gqlRouting'
|
||||
import { NftListV2Variant, useNftListV2Flag } from 'featureFlags/flags/nftListV2'
|
||||
import { useNftRouteLazyQuery } from 'graphql/data/__generated__/types-and-hooks'
|
||||
import { useIsNftDetailsPage, useIsNftPage, useIsNftProfilePage } from 'hooks/useIsNftPage'
|
||||
import { BagFooter } from 'nft/components/bag/BagFooter'
|
||||
import ListingModal from 'nft/components/bag/profile/ListingModal'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { Portal } from 'nft/components/common/Portal'
|
||||
import { Column } from 'nft/components/Flex'
|
||||
import { Overlay } from 'nft/components/modals/Overlay'
|
||||
import { buttonTextMedium, commonButtonStyles } from 'nft/css/common.css'
|
||||
import {
|
||||
useBag,
|
||||
useIsMobile,
|
||||
@@ -66,7 +64,7 @@ const BagContainer = styled.div<{ raiseZIndex: boolean; isProfilePage: boolean }
|
||||
border-radius: 16px;
|
||||
box-shadow: ${({ theme }) => theme.shallowShadow};
|
||||
z-index: ${({ raiseZIndex, isProfilePage }) =>
|
||||
raiseZIndex ? (isProfilePage ? Z_INDEX.modalOverTooltip : Z_INDEX.modalBackdrop + 2) : 3};
|
||||
raiseZIndex ? (isProfilePage ? Z_INDEX.modalOverTooltip : Z_INDEX.modalBackdrop - 1) : 3};
|
||||
|
||||
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
|
||||
right: 0px;
|
||||
@@ -90,6 +88,24 @@ const DetailsPageBackground = styled.div`
|
||||
height: 100%;
|
||||
`
|
||||
|
||||
const ContinueButton = styled.div`
|
||||
background: ${({ theme }) => theme.accentAction};
|
||||
color: ${({ theme }) => theme.accentTextLightPrimary};
|
||||
margin: 32px 28px 16px;
|
||||
padding: 10px 0px;
|
||||
border-radius: 12px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
transition: ${({ theme }) => theme.transition.duration.medium};
|
||||
|
||||
:hover {
|
||||
opacity: ${({ theme }) => theme.opacity.hover};
|
||||
}
|
||||
`
|
||||
|
||||
const ScrollingIndicator = ({ top, show }: SeparatorProps) => (
|
||||
<Box
|
||||
marginX="24"
|
||||
@@ -114,10 +130,7 @@ const Bag = () => {
|
||||
shallow
|
||||
)
|
||||
|
||||
const { profilePageState, setProfilePageState } = useProfilePageState(
|
||||
({ setProfilePageState, state }) => ({ profilePageState: state, setProfilePageState }),
|
||||
shallow
|
||||
)
|
||||
const { setProfilePageState } = useProfilePageState(({ setProfilePageState }) => ({ setProfilePageState }))
|
||||
|
||||
const {
|
||||
bagStatus,
|
||||
@@ -139,7 +152,6 @@ const Bag = () => {
|
||||
const isDetailsPage = useIsNftDetailsPage()
|
||||
const isNFTPage = useIsNftPage()
|
||||
const isMobile = useIsMobile()
|
||||
const isNftListV2 = useNftListV2Flag() === NftListV2Variant.Enabled
|
||||
const usingGqlRouting = useGqlRoutingFlag() === GqlRoutingVariant.Enabled
|
||||
|
||||
const sendTransaction = useSendTransaction((state) => state.sendTransaction)
|
||||
@@ -398,48 +410,34 @@ const Bag = () => {
|
||||
return (
|
||||
<Portal>
|
||||
<BagContainer data-testid="nft-bag" raiseZIndex={isMobile || isModalOpen} isProfilePage={isProfilePage}>
|
||||
{!(isProfilePage && profilePageState === ProfilePageStateType.LISTING) ? (
|
||||
<>
|
||||
<BagHeader
|
||||
numberOfAssets={isProfilePage ? sellAssets.length : itemsInBag.length}
|
||||
closeBag={handleCloseBag}
|
||||
resetFlow={isProfilePage ? resetSellAssets : reset}
|
||||
isProfilePage={isProfilePage}
|
||||
/>
|
||||
{shouldRenderEmptyState && <EmptyState />}
|
||||
<ScrollingIndicator top show={userCanScroll && scrollProgress > 0} />
|
||||
<Column ref={scrollRef} className={styles.assetsContainer} onScroll={scrollHandler} gap="12">
|
||||
{isProfilePage ? <ProfileBagContent /> : <BagContent />}
|
||||
</Column>
|
||||
{hasAssetsToShow && !isProfilePage && (
|
||||
<BagFooter totalEthPrice={totalEthPrice} fetchAssets={fetchAssets} eventProperties={eventProperties} />
|
||||
)}
|
||||
{isSellingAssets && isProfilePage && (
|
||||
<Box
|
||||
marginTop="32"
|
||||
marginX="28"
|
||||
marginBottom="16"
|
||||
paddingY="10"
|
||||
className={`${buttonTextMedium} ${commonButtonStyles}`}
|
||||
backgroundColor="accentAction"
|
||||
color="white"
|
||||
textAlign="center"
|
||||
onClick={() => {
|
||||
;(isMobile || isNftListV2) && toggleBag()
|
||||
setProfilePageState(ProfilePageStateType.LISTING)
|
||||
sendAnalyticsEvent(NFTEventName.NFT_PROFILE_PAGE_START_SELL, {
|
||||
list_quantity: sellAssets.length,
|
||||
collection_addresses: sellAssets.map((asset) => asset.asset_contract.address),
|
||||
token_ids: sellAssets.map((asset) => asset.tokenId),
|
||||
})
|
||||
}}
|
||||
>
|
||||
Continue
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<ListingModal />
|
||||
<BagHeader
|
||||
numberOfAssets={isProfilePage ? sellAssets.length : itemsInBag.length}
|
||||
closeBag={handleCloseBag}
|
||||
resetFlow={isProfilePage ? resetSellAssets : reset}
|
||||
isProfilePage={isProfilePage}
|
||||
/>
|
||||
{shouldRenderEmptyState && <EmptyState />}
|
||||
<ScrollingIndicator top show={userCanScroll && scrollProgress > 0} />
|
||||
<Column ref={scrollRef} className={styles.assetsContainer} onScroll={scrollHandler} gap="12">
|
||||
{isProfilePage ? <ProfileBagContent /> : <BagContent />}
|
||||
</Column>
|
||||
{hasAssetsToShow && !isProfilePage && (
|
||||
<BagFooter totalEthPrice={totalEthPrice} fetchAssets={fetchAssets} eventProperties={eventProperties} />
|
||||
)}
|
||||
{isSellingAssets && isProfilePage && (
|
||||
<ContinueButton
|
||||
onClick={() => {
|
||||
toggleBag()
|
||||
setProfilePageState(ProfilePageStateType.LISTING)
|
||||
sendAnalyticsEvent(NFTEventName.NFT_PROFILE_PAGE_START_SELL, {
|
||||
list_quantity: sellAssets.length,
|
||||
collection_addresses: sellAssets.map((asset) => asset.asset_contract.address),
|
||||
token_ids: sellAssets.map((asset) => asset.tokenId),
|
||||
})
|
||||
}}
|
||||
>
|
||||
<Trans>Continue</Trans>
|
||||
</ContinueButton>
|
||||
)}
|
||||
</BagContainer>
|
||||
|
||||
|
||||
@@ -4,8 +4,7 @@ import { parseEther } from '@ethersproject/units'
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { sendAnalyticsEvent, TraceEvent } from '@uniswap/analytics'
|
||||
import { BrowserEvent, InterfaceElementName, NFTEventName } from '@uniswap/analytics-events'
|
||||
import { formatPriceImpact } from '@uniswap/conedison/format'
|
||||
import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core'
|
||||
import { Currency, CurrencyAmount, Token, TradeType } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import Column from 'components/Column'
|
||||
import Loader from 'components/Loader'
|
||||
@@ -25,6 +24,7 @@ import { useBag } from 'nft/hooks/useBag'
|
||||
import useDerivedPayWithAnyTokenSwapInfo from 'nft/hooks/useDerivedPayWithAnyTokenSwapInfo'
|
||||
import usePayWithAnyTokenSwap from 'nft/hooks/usePayWithAnyTokenSwap'
|
||||
import usePermit2Approval from 'nft/hooks/usePermit2Approval'
|
||||
import { PriceImpact, usePriceImpact } from 'nft/hooks/usePriceImpact'
|
||||
import { useTokenInput } from 'nft/hooks/useTokenInput'
|
||||
import { useWalletBalance } from 'nft/hooks/useWalletBalance'
|
||||
import { BagStatus } from 'nft/types'
|
||||
@@ -35,14 +35,9 @@ import { useToggleWalletModal } from 'state/application/hooks'
|
||||
import { InterfaceTrade, TradeState } from 'state/routing/types'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
import { computeFiatValuePriceImpact } from 'utils/computeFiatValuePriceImpact'
|
||||
import { warningSeverity } from 'utils/prices'
|
||||
import { switchChain } from 'utils/switchChain'
|
||||
import shallow from 'zustand/shallow'
|
||||
|
||||
const LOW_SEVERITY_THRESHOLD = 1
|
||||
const MEDIUM_SEVERITY_THRESHOLD = 3
|
||||
|
||||
const FooterContainer = styled.div`
|
||||
padding: 0px 12px;
|
||||
`
|
||||
@@ -124,7 +119,7 @@ const PayButton = styled.button<{ $backgroundColor: string; $color: string }>`
|
||||
const FiatLoadingBubble = styled(LoadingBubble)`
|
||||
border-radius: 4px;
|
||||
width: 4rem;
|
||||
height: 1rem;
|
||||
height: 20px;
|
||||
align-self: end;
|
||||
`
|
||||
const PriceImpactContainer = styled(Row)`
|
||||
@@ -240,13 +235,11 @@ const InputCurrencyValue = ({
|
||||
const FiatValue = ({
|
||||
usdcValue,
|
||||
priceImpact,
|
||||
priceImpactColor,
|
||||
tradeState,
|
||||
usingPayWithAnyToken,
|
||||
}: {
|
||||
usdcValue: CurrencyAmount<Token> | null
|
||||
priceImpact: Percent | undefined
|
||||
priceImpactColor: string | undefined
|
||||
priceImpact: PriceImpact | undefined
|
||||
tradeState: TradeState
|
||||
usingPayWithAnyToken: boolean
|
||||
}) => {
|
||||
@@ -260,13 +253,13 @@ const FiatValue = ({
|
||||
|
||||
return (
|
||||
<PriceImpactContainer>
|
||||
{priceImpact && priceImpactColor && (
|
||||
{priceImpact && (
|
||||
<>
|
||||
<MouseoverTooltip text={t`The estimated difference between the USD values of input and output amounts.`}>
|
||||
<PriceImpactRow>
|
||||
<AlertTriangle color={priceImpactColor} size="16px" />
|
||||
<ThemedText.BodySmall style={{ color: priceImpactColor }} lineHeight="20px">
|
||||
(<Trans>{formatPriceImpact(priceImpact)}</Trans>)
|
||||
<AlertTriangle color={priceImpact.priceImpactSeverity.color} size="16px" />
|
||||
<ThemedText.BodySmall style={{ color: priceImpact.priceImpactSeverity.color }} lineHeight="20px">
|
||||
(<Trans>{priceImpact.displayPercentage()}</Trans>)
|
||||
</ThemedText.BodySmall>
|
||||
</PriceImpactRow>
|
||||
</MouseoverTooltip>
|
||||
@@ -342,30 +335,11 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo
|
||||
shouldUsePayWithAnyToken
|
||||
)
|
||||
usePayWithAnyTokenSwap(trade, allowance, allowedSlippage)
|
||||
const priceImpact = usePriceImpact(trade)
|
||||
|
||||
const fiatValueTradeInput = useStablecoinValue(trade?.inputAmount)
|
||||
const fiatValueTradeOutput = useStablecoinValue(parsedOutputAmount)
|
||||
const usdcValue = usingPayWithAnyToken ? fiatValueTradeInput : fiatValueTradeOutput
|
||||
const stablecoinPriceImpact = useMemo(
|
||||
() =>
|
||||
tradeState === TradeState.SYNCING || !trade
|
||||
? undefined
|
||||
: computeFiatValuePriceImpact(fiatValueTradeInput, fiatValueTradeOutput),
|
||||
[fiatValueTradeInput, fiatValueTradeOutput, tradeState, trade]
|
||||
)
|
||||
const { priceImpactWarning, priceImpactColor } = useMemo(() => {
|
||||
const severity = warningSeverity(stablecoinPriceImpact)
|
||||
|
||||
if (severity < LOW_SEVERITY_THRESHOLD) {
|
||||
return { priceImpactWarning: false, priceImpactColor: undefined }
|
||||
}
|
||||
|
||||
if (severity < MEDIUM_SEVERITY_THRESHOLD) {
|
||||
return { priceImpactWarning: false, priceImpactColor: theme.accentWarning }
|
||||
}
|
||||
|
||||
return { priceImpactWarning: true, priceImpactColor: theme.accentCritical }
|
||||
}, [stablecoinPriceImpact, theme.accentCritical, theme.accentWarning])
|
||||
|
||||
const { balance: balanceInEth } = useWalletBalance()
|
||||
const sufficientBalance = useMemo(() => {
|
||||
@@ -468,11 +442,11 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo
|
||||
warningTextColor = theme.accentAction
|
||||
warningText = <Trans>Price updated</Trans>
|
||||
buttonText = <Trans>Pay</Trans>
|
||||
} else if (priceImpactWarning && priceImpactColor) {
|
||||
} else if (priceImpact && priceImpact.priceImpactSeverity.type === 'error') {
|
||||
disabled = false
|
||||
buttonColor = priceImpactColor
|
||||
buttonColor = priceImpact.priceImpactSeverity.color
|
||||
helperText = <Trans>Price impact warning</Trans>
|
||||
helperTextColor = priceImpactColor
|
||||
helperTextColor = priceImpact.priceImpactSeverity.color
|
||||
buttonText = <Trans>Pay Anyway</Trans>
|
||||
} else if (sufficientBalance === true) {
|
||||
disabled = false
|
||||
@@ -506,8 +480,7 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo
|
||||
usingPayWithAnyToken,
|
||||
tradeState,
|
||||
allowance.state,
|
||||
priceImpactWarning,
|
||||
priceImpactColor,
|
||||
priceImpact,
|
||||
connector,
|
||||
toggleWalletModal,
|
||||
setBagExpanded,
|
||||
@@ -522,6 +495,8 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo
|
||||
...eventProperties,
|
||||
}
|
||||
|
||||
console.log(bagStatus)
|
||||
|
||||
return (
|
||||
<FooterContainer>
|
||||
<Footer>
|
||||
@@ -562,8 +537,7 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo
|
||||
</CurrencyRow>
|
||||
<FiatValue
|
||||
usdcValue={usdcValue}
|
||||
priceImpact={stablecoinPriceImpact}
|
||||
priceImpactColor={priceImpactColor}
|
||||
priceImpact={priceImpact}
|
||||
tradeState={tradeState}
|
||||
usingPayWithAnyToken={usingPayWithAnyToken}
|
||||
/>
|
||||
@@ -584,8 +558,7 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo
|
||||
</Row>
|
||||
<FiatValue
|
||||
usdcValue={usdcValue}
|
||||
priceImpact={stablecoinPriceImpact}
|
||||
priceImpactColor={priceImpactColor}
|
||||
priceImpact={priceImpact}
|
||||
tradeState={tradeState}
|
||||
usingPayWithAnyToken={usingPayWithAnyToken}
|
||||
/>
|
||||
@@ -602,7 +575,7 @@ export const BagFooter = ({ totalEthPrice, fetchAssets, eventProperties }: BagFo
|
||||
<Helper color={helperTextColor}>{helperText}</Helper>
|
||||
<ActionButton
|
||||
onClick={handleClick}
|
||||
disabled={disabled}
|
||||
disabled={disabled || isPending}
|
||||
backgroundColor={buttonColor}
|
||||
textColor={buttonTextColor}
|
||||
>
|
||||
|
||||
@@ -1,333 +0,0 @@
|
||||
import { Plural, t } from '@lingui/macro'
|
||||
import { NftListV2Variant, useNftListV2Flag } from 'featureFlags/flags/nftListV2'
|
||||
import { useOnClickOutside } from 'hooks/useOnClickOutside'
|
||||
import ms from 'ms.macro'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { Row } from 'nft/components/Flex'
|
||||
import { ArrowRightIcon, HazardIcon, LoadingIcon, XMarkIcon } from 'nft/components/icons'
|
||||
import { BelowFloorWarningModal } from 'nft/components/profile/list/Modal/BelowFloorWarningModal'
|
||||
import { bodySmall } from 'nft/css/common.css'
|
||||
import { themeVars } from 'nft/css/sprinkles.css'
|
||||
import { useNFTList, useSellAsset } from 'nft/hooks'
|
||||
import { Listing, ListingStatus, WalletAsset } from 'nft/types'
|
||||
import { pluralize } from 'nft/utils/roundAndPluralize'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTheme } from 'styled-components/macro'
|
||||
import shallow from 'zustand/shallow'
|
||||
|
||||
import * as styles from './ListingModal.css'
|
||||
import { getListings } from './utils'
|
||||
|
||||
const BELOW_FLOOR_PRICE_THRESHOLD = 0.8
|
||||
|
||||
interface ListingButtonProps {
|
||||
onClick: () => void
|
||||
buttonText: string
|
||||
showWarningOverride?: boolean
|
||||
}
|
||||
|
||||
export const ListingButton = ({ onClick, buttonText, showWarningOverride = false }: ListingButtonProps) => {
|
||||
const {
|
||||
addMarketplaceWarning,
|
||||
sellAssets,
|
||||
removeAllMarketplaceWarnings,
|
||||
showResolveIssues,
|
||||
toggleShowResolveIssues,
|
||||
issues,
|
||||
setIssues,
|
||||
} = useSellAsset(
|
||||
({
|
||||
addMarketplaceWarning,
|
||||
sellAssets,
|
||||
removeAllMarketplaceWarnings,
|
||||
showResolveIssues,
|
||||
toggleShowResolveIssues,
|
||||
issues,
|
||||
setIssues,
|
||||
}) => ({
|
||||
addMarketplaceWarning,
|
||||
sellAssets,
|
||||
removeAllMarketplaceWarnings,
|
||||
showResolveIssues,
|
||||
toggleShowResolveIssues,
|
||||
issues,
|
||||
setIssues,
|
||||
}),
|
||||
shallow
|
||||
)
|
||||
const { listingStatus, setListingStatus, setListings, setCollectionsRequiringApproval } = useNFTList(
|
||||
({ listingStatus, setListingStatus, setListings, setCollectionsRequiringApproval }) => ({
|
||||
listingStatus,
|
||||
setListingStatus,
|
||||
setListings,
|
||||
setCollectionsRequiringApproval,
|
||||
}),
|
||||
shallow
|
||||
)
|
||||
|
||||
const isNftListV2 = useNftListV2Flag() === NftListV2Variant.Enabled
|
||||
const [showWarning, setShowWarning] = useState(false)
|
||||
const [canContinue, setCanContinue] = useState(false)
|
||||
const theme = useTheme()
|
||||
const warningRef = useRef<HTMLDivElement>(null)
|
||||
useOnClickOutside(warningRef, () => {
|
||||
!isNftListV2 && setShowWarning(false)
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const [newCollectionsToApprove, newListings] = getListings(sellAssets)
|
||||
setListings(newListings)
|
||||
setCollectionsRequiringApproval(newCollectionsToApprove)
|
||||
setListingStatus(ListingStatus.DEFINED)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [sellAssets])
|
||||
|
||||
const [
|
||||
noMarketplacesSelected,
|
||||
missingExpiration,
|
||||
invalidExpiration,
|
||||
overMaxExpiration,
|
||||
listingsMissingPrice,
|
||||
listingsBelowFloor,
|
||||
listingsAboveSellOrderFloor,
|
||||
invalidPrices,
|
||||
] = useMemo(() => {
|
||||
const noMarketplacesSelected = sellAssets.some((asset: WalletAsset) => asset.marketplaces === undefined)
|
||||
const missingExpiration = sellAssets.some((asset) => {
|
||||
return (
|
||||
asset.expirationTime != null &&
|
||||
(isNaN(asset.expirationTime) || asset.expirationTime * 1000 - Date.now() < ms`60 seconds`)
|
||||
)
|
||||
})
|
||||
const invalidExpiration = sellAssets.some((asset) => {
|
||||
return asset.expirationTime != null && isNaN(asset.expirationTime)
|
||||
})
|
||||
const overMaxExpiration = sellAssets.some((asset) => {
|
||||
return asset.expirationTime != null && asset.expirationTime - Date.now() > ms`180 days`
|
||||
})
|
||||
const listingsMissingPrice: [WalletAsset, Listing][] = []
|
||||
const listingsBelowFloor: [WalletAsset, Listing][] = []
|
||||
const listingsAboveSellOrderFloor: [WalletAsset, Listing][] = []
|
||||
const invalidPrices: [WalletAsset, Listing][] = []
|
||||
for (const asset of sellAssets) {
|
||||
if (asset.newListings) {
|
||||
for (const listing of asset.newListings) {
|
||||
if (!listing.price) listingsMissingPrice.push([asset, listing])
|
||||
else if (isNaN(listing.price) || listing.price < 0) invalidPrices.push([asset, listing])
|
||||
else if (
|
||||
listing.price < (asset?.floorPrice ?? 0) * BELOW_FLOOR_PRICE_THRESHOLD &&
|
||||
!listing.overrideFloorPrice
|
||||
)
|
||||
listingsBelowFloor.push([asset, listing])
|
||||
else if (asset.floor_sell_order_price && listing.price >= asset.floor_sell_order_price)
|
||||
listingsAboveSellOrderFloor.push([asset, listing])
|
||||
}
|
||||
}
|
||||
}
|
||||
// set number of issues
|
||||
if (isNftListV2) {
|
||||
const foundIssues =
|
||||
Number(missingExpiration) +
|
||||
Number(overMaxExpiration) +
|
||||
listingsMissingPrice.length +
|
||||
listingsAboveSellOrderFloor.length
|
||||
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)
|
||||
toggleShowResolveIssues()
|
||||
}
|
||||
|
||||
const continueCheck = listingsBelowFloor.length === 0 && listingsAboveSellOrderFloor.length === 0
|
||||
setCanContinue(continueCheck)
|
||||
return [
|
||||
noMarketplacesSelected,
|
||||
missingExpiration,
|
||||
invalidExpiration,
|
||||
overMaxExpiration,
|
||||
listingsMissingPrice,
|
||||
listingsBelowFloor,
|
||||
listingsAboveSellOrderFloor,
|
||||
invalidPrices,
|
||||
]
|
||||
}, [isNftListV2, sellAssets, setIssues, showResolveIssues, toggleShowResolveIssues])
|
||||
|
||||
const [disableListButton, warningMessage] = useMemo(() => {
|
||||
const disableListButton =
|
||||
noMarketplacesSelected ||
|
||||
missingExpiration ||
|
||||
invalidExpiration ||
|
||||
overMaxExpiration ||
|
||||
invalidPrices.length > 0 ||
|
||||
listingsMissingPrice.length > 0
|
||||
|
||||
const warningMessage = noMarketplacesSelected
|
||||
? 'No marketplaces selected'
|
||||
: missingExpiration
|
||||
? 'Set duration'
|
||||
: invalidExpiration
|
||||
? 'Invalid duration'
|
||||
: overMaxExpiration
|
||||
? 'Max duration is 6 months'
|
||||
: listingsMissingPrice.length > 0
|
||||
? `${listingsMissingPrice.length} item price${pluralize(listingsMissingPrice.length)} not set`
|
||||
: invalidPrices.length > 0
|
||||
? `${invalidPrices.length} price${pluralize(invalidPrices.length)} are invalid`
|
||||
: listingsBelowFloor.length > 0
|
||||
? `${listingsBelowFloor.length} item${pluralize(listingsBelowFloor.length)} listed below floor`
|
||||
: listingsAboveSellOrderFloor.length > 0
|
||||
? `${listingsAboveSellOrderFloor.length} item${pluralize(listingsAboveSellOrderFloor.length)} already listed`
|
||||
: ''
|
||||
return [disableListButton, warningMessage]
|
||||
}, [
|
||||
noMarketplacesSelected,
|
||||
missingExpiration,
|
||||
invalidExpiration,
|
||||
overMaxExpiration,
|
||||
listingsMissingPrice,
|
||||
invalidPrices,
|
||||
listingsBelowFloor,
|
||||
listingsAboveSellOrderFloor,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
setShowWarning(false)
|
||||
}, [warningMessage])
|
||||
|
||||
const addWarningMessages = () => {
|
||||
removeAllMarketplaceWarnings()
|
||||
if (!missingExpiration && !noMarketplacesSelected) {
|
||||
if (listingsMissingPrice.length > 0) {
|
||||
for (const [asset, listing] of listingsMissingPrice) {
|
||||
addMarketplaceWarning(asset, {
|
||||
message: 'PLEASE SET A PRICE',
|
||||
marketplace: listing.marketplace,
|
||||
})
|
||||
}
|
||||
} else if (invalidPrices.length > 0) {
|
||||
for (const [asset, listing] of invalidPrices) {
|
||||
!listing.overrideFloorPrice &&
|
||||
addMarketplaceWarning(asset, {
|
||||
message: `INVALID PRICE`,
|
||||
marketplace: listing.marketplace,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
setShowWarning(true)
|
||||
}
|
||||
|
||||
const warningWrappedClick = () => {
|
||||
if ((!disableListButton && canContinue) || showWarningOverride) {
|
||||
if (issues && isNftListV2) !showResolveIssues && toggleShowResolveIssues()
|
||||
else if (listingsBelowFloor.length) setShowWarning(true)
|
||||
else onClick()
|
||||
} else addWarningMessages()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box position="relative">
|
||||
{!showWarningOverride && showWarning && warningMessage.length > 0 && (
|
||||
<Row
|
||||
className={`${bodySmall} ${styles.warningTooltip}`}
|
||||
transition="250"
|
||||
onClick={() => setShowWarning(false)}
|
||||
color="textSecondary"
|
||||
zIndex="3"
|
||||
borderRadius="4"
|
||||
backgroundColor="backgroundSurface"
|
||||
height={!disableListButton ? '64' : '36'}
|
||||
maxWidth="276"
|
||||
position="absolute"
|
||||
left="24"
|
||||
bottom="52"
|
||||
flexWrap={!disableListButton ? 'wrap' : 'nowrap'}
|
||||
style={{ maxWidth: !disableListButton ? '225px' : '' }}
|
||||
ref={warningRef}
|
||||
>
|
||||
<HazardIcon />
|
||||
<Box marginLeft="4" marginRight="8">
|
||||
{warningMessage}
|
||||
</Box>
|
||||
{disableListButton ? (
|
||||
<Box paddingTop="6">
|
||||
<XMarkIcon fill={themeVars.colors.textSecondary} height="20" width="20" />
|
||||
</Box>
|
||||
) : (
|
||||
<Row
|
||||
marginLeft="72"
|
||||
cursor="pointer"
|
||||
color="accentAction"
|
||||
onClick={() => {
|
||||
setShowWarning(false)
|
||||
setCanContinue(true)
|
||||
onClick()
|
||||
}}
|
||||
>
|
||||
Continue
|
||||
<ArrowRightIcon height="20" width="20" />
|
||||
</Row>
|
||||
)}
|
||||
</Row>
|
||||
)}
|
||||
<Box
|
||||
as="button"
|
||||
border="none"
|
||||
backgroundColor={showResolveIssues ? 'accentFailure' : 'accentAction'}
|
||||
cursor={
|
||||
[ListingStatus.APPROVED, ListingStatus.PENDING, ListingStatus.SIGNING].includes(listingStatus) ||
|
||||
disableListButton
|
||||
? 'default'
|
||||
: 'pointer'
|
||||
}
|
||||
className={styles.button}
|
||||
onClick={() => listingStatus !== ListingStatus.APPROVED && warningWrappedClick()}
|
||||
type="button"
|
||||
style={{
|
||||
color: showResolveIssues ? theme.accentTextDarkPrimary : theme.white,
|
||||
opacity:
|
||||
![ListingStatus.DEFINED, ListingStatus.FAILED, ListingStatus.CONTINUE].includes(listingStatus) ||
|
||||
(disableListButton && !showResolveIssues)
|
||||
? 0.3
|
||||
: 1,
|
||||
}}
|
||||
>
|
||||
{listingStatus === ListingStatus.SIGNING || listingStatus === ListingStatus.PENDING ? (
|
||||
isNftListV2 ? (
|
||||
listingStatus === ListingStatus.PENDING ? (
|
||||
'Pending'
|
||||
) : (
|
||||
'Proceed in wallet'
|
||||
)
|
||||
) : (
|
||||
<Row gap="8">
|
||||
<LoadingIcon stroke="backgroundSurface" height="20" width="20" />
|
||||
{listingStatus === ListingStatus.PENDING ? 'Pending' : 'Proceed in wallet'}
|
||||
</Row>
|
||||
)
|
||||
) : listingStatus === ListingStatus.APPROVED ? (
|
||||
'Complete!'
|
||||
) : listingStatus === ListingStatus.PAUSED ? (
|
||||
'Paused'
|
||||
) : listingStatus === ListingStatus.FAILED ? (
|
||||
'Try again'
|
||||
) : listingStatus === ListingStatus.CONTINUE ? (
|
||||
'Continue'
|
||||
) : showResolveIssues ? (
|
||||
<Plural value={issues !== 1 ? 2 : 1} _1="Resolve issue" other={t`Resolve ${issues} issues`} />
|
||||
) : (
|
||||
buttonText
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
{showWarning && (
|
||||
<BelowFloorWarningModal
|
||||
listingsBelowFloor={listingsBelowFloor}
|
||||
closeModal={() => setShowWarning(false)}
|
||||
startListing={onClick}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import { style } from '@vanilla-extract/css'
|
||||
import { sprinkles } from 'nft/css/sprinkles.css'
|
||||
|
||||
export const chevron = style([
|
||||
sprinkles({
|
||||
height: '28',
|
||||
width: '28',
|
||||
transition: '250',
|
||||
marginLeft: 'auto',
|
||||
marginRight: '0',
|
||||
}),
|
||||
])
|
||||
|
||||
export const chevronDown = style({
|
||||
transform: 'rotate(180deg)',
|
||||
cursor: 'pointer',
|
||||
})
|
||||
|
||||
export const sectionDivider = style([
|
||||
sprinkles({
|
||||
borderRadius: '20',
|
||||
marginTop: '8',
|
||||
width: 'full',
|
||||
borderWidth: '0.5px',
|
||||
borderStyle: 'solid',
|
||||
borderColor: 'backgroundOutline',
|
||||
}),
|
||||
])
|
||||
|
||||
export const button = style([
|
||||
sprinkles({
|
||||
paddingX: { sm: '12', md: '16' },
|
||||
paddingY: { sm: '10', md: '16' },
|
||||
textAlign: 'center',
|
||||
fontWeight: 'semibold',
|
||||
fontSize: { sm: '16', md: '20' },
|
||||
lineHeight: { sm: '20', md: '24' },
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
alignSelf: 'flex-end',
|
||||
borderRadius: '12',
|
||||
}),
|
||||
])
|
||||
|
||||
export const listingModalIcon = style([
|
||||
sprinkles({
|
||||
borderWidth: '1px',
|
||||
borderStyle: 'solid',
|
||||
borderColor: 'backgroundSurface',
|
||||
}),
|
||||
{
|
||||
boxSizing: 'border-box',
|
||||
marginLeft: '-2px',
|
||||
marginRight: '4px',
|
||||
},
|
||||
])
|
||||
|
||||
export const warningTooltip = style([
|
||||
sprinkles({
|
||||
paddingTop: '8',
|
||||
paddingRight: '8',
|
||||
paddingBottom: '8',
|
||||
paddingLeft: '12',
|
||||
}),
|
||||
{
|
||||
boxShadow: '0px 4px 16px rgba(10, 10, 59, 0.2)',
|
||||
},
|
||||
])
|
||||
|
||||
export const listingSectionBorder = style([
|
||||
sprinkles({
|
||||
padding: '8',
|
||||
borderRadius: '8',
|
||||
borderColor: 'backgroundOutline',
|
||||
borderStyle: 'solid',
|
||||
borderWidth: '1px',
|
||||
}),
|
||||
])
|
||||
@@ -1,322 +0,0 @@
|
||||
import { sendAnalyticsEvent, Trace, useTrace } from '@uniswap/analytics'
|
||||
import { InterfaceModalName, NFTEventName } from '@uniswap/analytics-events'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { Column, Row } from 'nft/components/Flex'
|
||||
import { ChevronLeftIcon, XMarkIcon } from 'nft/components/icons'
|
||||
import { caption, headlineSmall, subhead, subheadSmall } from 'nft/css/common.css'
|
||||
import { themeVars } from 'nft/css/sprinkles.css'
|
||||
import { useBag, useIsMobile, useNFTList, useSellAsset } from 'nft/hooks'
|
||||
import { logListing, looksRareNonceFetcher } from 'nft/queries'
|
||||
import { AssetRow, CollectionRow, ListingRow, ListingStatus } from 'nft/types'
|
||||
import { fetchPrice } from 'nft/utils/fetchPrice'
|
||||
import { pluralize } from 'nft/utils/roundAndPluralize'
|
||||
import { Dispatch, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import shallow from 'zustand/shallow'
|
||||
|
||||
import { ListingButton } from './ListingButton'
|
||||
import * as styles from './ListingModal.css'
|
||||
import { ListingSection } from './ListingSection'
|
||||
import { approveCollectionRow, getTotalEthValue, pauseRow, resetRow, signListingRow, verifyStatus } from './utils'
|
||||
|
||||
const ListingModal = () => {
|
||||
const { provider } = useWeb3React()
|
||||
const sellAssets = useSellAsset((state) => state.sellAssets)
|
||||
const {
|
||||
listingStatus,
|
||||
setListingStatus,
|
||||
setListings,
|
||||
setCollectionsRequiringApproval,
|
||||
setListingStatusAndCallback,
|
||||
setCollectionStatusAndCallback,
|
||||
looksRareNonce,
|
||||
setLooksRareNonce,
|
||||
getLooksRareNonce,
|
||||
collectionsRequiringApproval,
|
||||
listings,
|
||||
} = useNFTList(
|
||||
({
|
||||
listingStatus,
|
||||
setListingStatus,
|
||||
setListings,
|
||||
setCollectionsRequiringApproval,
|
||||
setListingStatusAndCallback,
|
||||
setCollectionStatusAndCallback,
|
||||
looksRareNonce,
|
||||
setLooksRareNonce,
|
||||
getLooksRareNonce,
|
||||
collectionsRequiringApproval,
|
||||
listings,
|
||||
}) => ({
|
||||
listingStatus,
|
||||
setListingStatus,
|
||||
setListings,
|
||||
setCollectionsRequiringApproval,
|
||||
setListingStatusAndCallback,
|
||||
setCollectionStatusAndCallback,
|
||||
looksRareNonce,
|
||||
setLooksRareNonce,
|
||||
getLooksRareNonce,
|
||||
collectionsRequiringApproval,
|
||||
listings,
|
||||
}),
|
||||
shallow
|
||||
)
|
||||
const signer = provider?.getSigner()
|
||||
const [openIndex, setOpenIndex] = useState(0)
|
||||
const [allCollectionsApproved, setAllCollectionsApproved] = useState(false)
|
||||
const toggleCart = useBag((state) => state.toggleBag)
|
||||
const looksRareNonceRef = useRef(looksRareNonce)
|
||||
const isMobile = useIsMobile()
|
||||
const trace = useTrace({ modal: InterfaceModalName.NFT_LISTING })
|
||||
|
||||
useEffect(() => {
|
||||
useNFTList.subscribe((state) => (looksRareNonceRef.current = state.looksRareNonce))
|
||||
}, [])
|
||||
|
||||
const totalEthListingValue = useMemo(() => getTotalEthValue(sellAssets), [sellAssets])
|
||||
|
||||
const [ethPriceInUSD, setEthPriceInUSD] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
fetchPrice().then((price) => {
|
||||
setEthPriceInUSD(price || 0)
|
||||
})
|
||||
}, [])
|
||||
|
||||
const startListingEventProperties = {
|
||||
collection_addresses: sellAssets.map((asset) => asset.asset_contract.address),
|
||||
token_ids: sellAssets.map((asset) => asset.tokenId),
|
||||
marketplaces: Array.from(new Set(listings.map((asset) => asset.marketplace.name))),
|
||||
list_quantity: listings.length,
|
||||
usd_value: ethPriceInUSD * totalEthListingValue,
|
||||
...trace,
|
||||
}
|
||||
|
||||
// when all collections have been approved, auto start the signing process
|
||||
useEffect(() => {
|
||||
collectionsRequiringApproval?.length &&
|
||||
setAllCollectionsApproved(
|
||||
collectionsRequiringApproval.every((collection: CollectionRow) => collection.status === ListingStatus.APPROVED)
|
||||
)
|
||||
if (
|
||||
allCollectionsApproved &&
|
||||
(listingStatus === ListingStatus.PENDING ||
|
||||
listingStatus === ListingStatus.CONTINUE ||
|
||||
listingStatus === ListingStatus.SIGNING)
|
||||
) {
|
||||
resetAllRows()
|
||||
signListings()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [collectionsRequiringApproval, allCollectionsApproved])
|
||||
|
||||
const allCollectionsApprovedOrPaused = useMemo(
|
||||
() =>
|
||||
collectionsRequiringApproval.every(
|
||||
(collection: CollectionRow) =>
|
||||
collection.status === ListingStatus.APPROVED || collection.status === ListingStatus.PAUSED
|
||||
),
|
||||
[collectionsRequiringApproval]
|
||||
)
|
||||
const allListingsApprovedOrPaused = useMemo(
|
||||
() =>
|
||||
listings.every(
|
||||
(listing: ListingRow) => listing.status === ListingStatus.APPROVED || listing.status === ListingStatus.PAUSED
|
||||
),
|
||||
[listings]
|
||||
)
|
||||
|
||||
// go back to a ready state after a successful retry
|
||||
useEffect(() => {
|
||||
if (listingStatus === ListingStatus.SIGNING && allCollectionsApprovedOrPaused && allListingsApprovedOrPaused) {
|
||||
resetAllRows()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [allCollectionsApprovedOrPaused, allListingsApprovedOrPaused])
|
||||
|
||||
// handles the modal wide listing state based on conglomeration of the wallet, collection, and listing states
|
||||
const startListingFlow = async () => {
|
||||
if (!signer) return
|
||||
sendAnalyticsEvent(NFTEventName.NFT_SELL_START_LISTING, { ...startListingEventProperties })
|
||||
setListingStatus(ListingStatus.SIGNING)
|
||||
const signerAddress = await signer.getAddress()
|
||||
const nonce = await looksRareNonceFetcher(signerAddress)
|
||||
setLooksRareNonce(nonce ?? 0)
|
||||
|
||||
if (!collectionsRequiringApproval?.some((collection) => collection.status === ListingStatus.PAUSED)) {
|
||||
setListingStatus(ListingStatus.SIGNING)
|
||||
setOpenIndex(1)
|
||||
}
|
||||
// for all unique collection, marketplace combos -> approve collections
|
||||
for (const collectionRow of collectionsRequiringApproval) {
|
||||
verifyStatus(collectionRow.status) &&
|
||||
(isMobile
|
||||
? await approveCollectionRow(collectionRow, signer, setCollectionStatusAndCallback, pauseAllRows)
|
||||
: approveCollectionRow(collectionRow, signer, setCollectionStatusAndCallback, pauseAllRows))
|
||||
}
|
||||
}
|
||||
|
||||
const signListings = async () => {
|
||||
if (!signer || !provider) return
|
||||
setListingStatus(ListingStatus.SIGNING)
|
||||
setOpenIndex(2)
|
||||
// sign listings
|
||||
for (const listing of listings) {
|
||||
verifyStatus(listing.status) &&
|
||||
(await signListingRow(
|
||||
listing,
|
||||
signer,
|
||||
provider,
|
||||
getLooksRareNonce,
|
||||
setLooksRareNonce,
|
||||
setListingStatusAndCallback,
|
||||
pauseAllRows
|
||||
))
|
||||
}
|
||||
const allListingsSigned = listings.every((listing: ListingRow) => listing.status === ListingStatus.APPROVED)
|
||||
const paused = listings.some((listing: ListingRow) => listing.status === ListingStatus.PAUSED)
|
||||
if (allListingsSigned) {
|
||||
setOpenIndex(0)
|
||||
setListingStatus(ListingStatus.APPROVED)
|
||||
} else if (!paused) {
|
||||
setListingStatus(ListingStatus.FAILED)
|
||||
}
|
||||
sendAnalyticsEvent(NFTEventName.NFT_LISTING_COMPLETED, {
|
||||
signatures_approved: listings.filter((asset) => asset.status === ListingStatus.APPROVED),
|
||||
list_quantity: listings.length,
|
||||
usd_value: ethPriceInUSD * totalEthListingValue,
|
||||
...trace,
|
||||
})
|
||||
await logListing(listings, (await signer?.getAddress()) ?? '')
|
||||
}
|
||||
|
||||
const pauseAllRows = () => {
|
||||
for (const collection of collectionsRequiringApproval) {
|
||||
pauseRow(collection, collectionsRequiringApproval, setCollectionsRequiringApproval as Dispatch<AssetRow[]>)
|
||||
}
|
||||
for (const listing of listings) {
|
||||
pauseRow(listing, listings, setListings as Dispatch<AssetRow[]>)
|
||||
}
|
||||
}
|
||||
|
||||
const resetAllRows = () => {
|
||||
for (const collection of collectionsRequiringApproval) {
|
||||
resetRow(collection, collectionsRequiringApproval, setCollectionsRequiringApproval as Dispatch<AssetRow[]>)
|
||||
}
|
||||
for (const listing of listings) {
|
||||
resetRow(listing, listings, setListings as Dispatch<AssetRow[]>)
|
||||
}
|
||||
}
|
||||
|
||||
const clickStopListing = () => {
|
||||
pauseAllRows()
|
||||
}
|
||||
|
||||
const clickStartListingFlow = () => {
|
||||
resetAllRows()
|
||||
allCollectionsApproved ? signListings() : startListingFlow()
|
||||
}
|
||||
|
||||
const showSuccessScreen = useMemo(() => listingStatus === ListingStatus.APPROVED, [listingStatus])
|
||||
|
||||
return (
|
||||
<Trace modal={InterfaceModalName.NFT_LISTING}>
|
||||
<Column paddingTop="20" paddingBottom="20" paddingLeft="12" paddingRight="12">
|
||||
<Row className={headlineSmall} marginBottom="10">
|
||||
{isMobile && !showSuccessScreen && (
|
||||
<Box paddingTop="4" marginRight="4" onClick={toggleCart}>
|
||||
<ChevronLeftIcon height={28} width={28} />
|
||||
</Box>
|
||||
)}
|
||||
{showSuccessScreen ? 'Success!' : `Listing ${sellAssets.length} NFTs`}
|
||||
<Box
|
||||
as="button"
|
||||
border="none"
|
||||
color="textSecondary"
|
||||
backgroundColor="backgroundSurface"
|
||||
marginLeft="auto"
|
||||
marginRight="0"
|
||||
paddingRight="0"
|
||||
display={{ sm: 'flex', md: 'none' }}
|
||||
cursor="pointer"
|
||||
onClick={toggleCart}
|
||||
>
|
||||
<XMarkIcon height={28} width={28} fill={themeVars.colors.textPrimary} />
|
||||
</Box>
|
||||
</Row>
|
||||
<Column overflowX="hidden" overflowY="auto" style={{ maxHeight: '60vh' }}>
|
||||
{showSuccessScreen ? (
|
||||
<Trace
|
||||
name={NFTEventName.NFT_LISTING_COMPLETED}
|
||||
properties={{ list_quantity: listings.length, usd_value: ethPriceInUSD * totalEthListingValue, ...trace }}
|
||||
shouldLogImpression
|
||||
>
|
||||
<ListingSection
|
||||
sectionTitle={`Listed ${listings.length} item${pluralize(listings.length)} for sale`}
|
||||
rows={listings}
|
||||
index={0}
|
||||
openIndex={openIndex}
|
||||
isSuccessScreen={true}
|
||||
/>
|
||||
</Trace>
|
||||
) : (
|
||||
<>
|
||||
<ListingSection
|
||||
sectionTitle={`Approve ${collectionsRequiringApproval.length} collection${pluralize(
|
||||
collectionsRequiringApproval.length
|
||||
)}`}
|
||||
title="COLLECTIONS"
|
||||
rows={collectionsRequiringApproval}
|
||||
index={1}
|
||||
openIndex={openIndex}
|
||||
/>
|
||||
<ListingSection
|
||||
sectionTitle={`Confirm ${listings.length} listing${pluralize(listings.length)}`}
|
||||
caption="Now you can sign to list each item"
|
||||
title="NFTS"
|
||||
rows={listings}
|
||||
index={2}
|
||||
openIndex={openIndex}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Column>
|
||||
<hr className={styles.sectionDivider} />
|
||||
<Row className={subhead} marginTop="12" marginBottom={showSuccessScreen ? '8' : '20'}>
|
||||
Return if sold
|
||||
<Row className={subheadSmall} marginLeft="auto" marginRight="0">
|
||||
{totalEthListingValue}
|
||||
ETH
|
||||
</Row>
|
||||
</Row>
|
||||
{showSuccessScreen ? (
|
||||
<Box as="span" className={caption} color="textSecondary">
|
||||
Status:{' '}
|
||||
<Box as="span" color="accentSuccess">
|
||||
Confirmed
|
||||
</Box>
|
||||
</Box>
|
||||
) : (
|
||||
<ListingButton onClick={clickStartListingFlow} buttonText="Start listing" showWarningOverride={isMobile} />
|
||||
)}
|
||||
{(listingStatus === ListingStatus.PENDING || listingStatus === ListingStatus.SIGNING) && (
|
||||
<Box
|
||||
as="button"
|
||||
border="none"
|
||||
backgroundColor="backgroundSurface"
|
||||
cursor="pointer"
|
||||
color="orange"
|
||||
className={styles.button}
|
||||
onClick={clickStopListing}
|
||||
type="button"
|
||||
>
|
||||
Stop listing
|
||||
</Box>
|
||||
)}
|
||||
</Column>
|
||||
</Trace>
|
||||
)
|
||||
}
|
||||
|
||||
export default ListingModal
|
||||
@@ -1,187 +0,0 @@
|
||||
import clsx from 'clsx'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { Column, Row } from 'nft/components/Flex'
|
||||
import { ApprovedCheckmarkIcon, ChevronUpIcon, FailedListingIcon, LoadingIcon } from 'nft/components/icons'
|
||||
import { badge, bodySmall, buttonTextSmall, subhead } from 'nft/css/common.css'
|
||||
import { useSellAsset } from 'nft/hooks'
|
||||
import { AssetRow, CollectionRow, ListingRow, ListingStatus } from 'nft/types'
|
||||
import { formatEthPrice, numberToWei } from 'nft/utils/currency'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import * as styles from './ListingModal.css'
|
||||
|
||||
export const ListingSection = ({
|
||||
sectionTitle,
|
||||
caption = undefined,
|
||||
title = undefined,
|
||||
rows,
|
||||
index,
|
||||
openIndex,
|
||||
isSuccessScreen = false,
|
||||
}: {
|
||||
sectionTitle: string
|
||||
caption?: string
|
||||
title?: string
|
||||
rows: AssetRow[]
|
||||
index: number
|
||||
openIndex: number
|
||||
isSuccessScreen?: boolean
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const notAllApproved = rows.some((row: AssetRow) => row.status !== ListingStatus.APPROVED)
|
||||
const sellAssets = useSellAsset((state) => state.sellAssets)
|
||||
const removeAssetMarketplace = useSellAsset((state) => state.removeAssetMarketplace)
|
||||
|
||||
const removeRow = (row: any) => {
|
||||
// collections
|
||||
if (index === 1) {
|
||||
for (const asset of sellAssets)
|
||||
if (asset.asset_contract.address === row.collectionAddress) removeAssetMarketplace(asset, row.marketplace)
|
||||
}
|
||||
// listings
|
||||
else removeAssetMarketplace(row.asset, row.marketplace)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setIsOpen(index === openIndex)
|
||||
}, [index, openIndex])
|
||||
|
||||
function getListingRowPrice(row: AssetRow): number | undefined {
|
||||
const listingRow = row as ListingRow
|
||||
const newListings = listingRow.asset.newListings
|
||||
return newListings?.find((listing) => listing.marketplace.name === listingRow.marketplace.name)?.price ?? 0
|
||||
}
|
||||
|
||||
const allApproved = !notAllApproved && rows.length > 0 && !isSuccessScreen
|
||||
|
||||
return (
|
||||
<Row
|
||||
flexWrap="wrap"
|
||||
className={subhead}
|
||||
marginTop="10"
|
||||
marginBottom="10"
|
||||
onClick={() => rows.length > 0 && setIsOpen(!isOpen)}
|
||||
color={allApproved ? 'accentSuccess' : 'textPrimary'}
|
||||
>
|
||||
{allApproved && <ApprovedCheckmarkIcon style={{ marginRight: '8px' }} />}
|
||||
{sectionTitle}
|
||||
{!isSuccessScreen && <ChevronUpIcon className={clsx(`${isOpen ? '' : styles.chevronDown} ${styles.chevron}`)} />}
|
||||
{(isOpen || isSuccessScreen) && (
|
||||
<Column
|
||||
gap="12"
|
||||
width="full"
|
||||
paddingTop={isSuccessScreen ? '28' : 'auto'}
|
||||
className={clsx(!isSuccessScreen && styles.listingSectionBorder)}
|
||||
>
|
||||
{caption && (
|
||||
<Box color="textPrimary" fontWeight="normal" className={caption}>
|
||||
{caption}
|
||||
</Box>
|
||||
)}
|
||||
{title && (
|
||||
<Box color="textSecondary" className={badge}>
|
||||
{title}
|
||||
</Box>
|
||||
)}
|
||||
<Column gap="8">
|
||||
{rows.map((row: AssetRow, index) => {
|
||||
return (
|
||||
<Column key={index} gap="8">
|
||||
<Row>
|
||||
{row.images?.map((image, index) => {
|
||||
return (
|
||||
<Box
|
||||
as="img"
|
||||
height="20"
|
||||
width="20"
|
||||
borderRadius={index === 0 && (row as CollectionRow).collectionAddress ? 'round' : '4'}
|
||||
style={{ zIndex: 2 - index }}
|
||||
className={styles.listingModalIcon}
|
||||
src={image}
|
||||
alt={row.name}
|
||||
key={index}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
<Box
|
||||
marginLeft="8"
|
||||
marginRight="auto"
|
||||
fontWeight="normal"
|
||||
color="textPrimary"
|
||||
textOverflow="ellipsis"
|
||||
overflow="hidden"
|
||||
whiteSpace="nowrap"
|
||||
maxWidth={{
|
||||
sm: 'max',
|
||||
md:
|
||||
row.status === ListingStatus.REJECTED || row.status === ListingStatus.FAILED ? '120' : 'full',
|
||||
}}
|
||||
className={bodySmall}
|
||||
>
|
||||
{row.name}
|
||||
</Box>
|
||||
{isSuccessScreen ? (
|
||||
getListingRowPrice(row) &&
|
||||
`${formatEthPrice(numberToWei(getListingRowPrice(row) ?? 0).toString())} ETH`
|
||||
) : row.status === ListingStatus.APPROVED ? (
|
||||
<ApprovedCheckmarkIcon height="20" width="20" />
|
||||
) : row.status === ListingStatus.FAILED || row.status === ListingStatus.REJECTED ? (
|
||||
<Row gap="4">
|
||||
<Box fontWeight="normal" fontSize="14" color="textSecondary">
|
||||
{row.status}
|
||||
</Box>
|
||||
<FailedListingIcon />
|
||||
</Row>
|
||||
) : (
|
||||
row.status === ListingStatus.SIGNING && <LoadingIcon height="20" width="20" stroke="#4673FA" />
|
||||
)}
|
||||
</Row>
|
||||
{(row.status === ListingStatus.FAILED || row.status === ListingStatus.REJECTED) && (
|
||||
<Row gap="8" justifyContent="center">
|
||||
<Box
|
||||
width="120"
|
||||
as="button"
|
||||
className={buttonTextSmall}
|
||||
borderRadius="12"
|
||||
border="none"
|
||||
color="red400"
|
||||
height="32"
|
||||
cursor="pointer"
|
||||
style={{ backgroundColor: '#FA2B391A' }}
|
||||
onClick={async (e) => {
|
||||
e.stopPropagation()
|
||||
removeRow(row)
|
||||
}}
|
||||
>
|
||||
Remove
|
||||
</Box>
|
||||
<Box
|
||||
width="120"
|
||||
as="button"
|
||||
className={buttonTextSmall}
|
||||
borderRadius="12"
|
||||
border="none"
|
||||
color="accentAction"
|
||||
height="32"
|
||||
cursor="pointer"
|
||||
style={{ backgroundColor: '#4C82FB29' }}
|
||||
onClick={async (e) => {
|
||||
e.stopPropagation()
|
||||
if (row.callback) {
|
||||
await row.callback()
|
||||
}
|
||||
}}
|
||||
>
|
||||
Try again
|
||||
</Box>
|
||||
</Row>
|
||||
)}
|
||||
</Column>
|
||||
)
|
||||
})}
|
||||
</Column>
|
||||
</Column>
|
||||
)}
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
@@ -2,30 +2,8 @@ import type { JsonRpcSigner, Web3Provider } from '@ethersproject/providers'
|
||||
import { addressesByNetwork, SupportedChainId } from '@looksrare/sdk'
|
||||
import { LOOKSRARE_MARKETPLACE_CONTRACT, X2Y2_TRANSFER_CONTRACT } from 'nft/queries'
|
||||
import { OPENSEA_CROSS_CHAIN_CONDUIT } from 'nft/queries/openSea'
|
||||
import { AssetRow, CollectionRow, ListingMarket, ListingRow, ListingStatus, WalletAsset } from 'nft/types'
|
||||
import { CollectionRow, ListingMarket, ListingRow, ListingStatus, WalletAsset } from 'nft/types'
|
||||
import { approveCollection, LOOKS_RARE_CREATOR_BASIS_POINTS, signListing } from 'nft/utils/listNfts'
|
||||
import { Dispatch } from 'react'
|
||||
|
||||
const updateStatus = ({
|
||||
listing,
|
||||
newStatus,
|
||||
rows,
|
||||
setRows,
|
||||
callback,
|
||||
}: {
|
||||
listing: AssetRow
|
||||
newStatus: ListingStatus
|
||||
rows: AssetRow[]
|
||||
setRows: Dispatch<AssetRow[]>
|
||||
callback?: () => Promise<void>
|
||||
}) => {
|
||||
const rowsCopy = [...rows]
|
||||
const index = rows.findIndex((n) => n === listing)
|
||||
listing.status = newStatus
|
||||
if (callback) listing.callback = callback
|
||||
rowsCopy[index] = listing
|
||||
setRows(rowsCopy)
|
||||
}
|
||||
|
||||
export async function approveCollectionRow(
|
||||
collectionRow: CollectionRow,
|
||||
@@ -211,27 +189,3 @@ export const getListingState = (
|
||||
export const verifyStatus = (status: ListingStatus) => {
|
||||
return status !== ListingStatus.PAUSED && status !== ListingStatus.APPROVED
|
||||
}
|
||||
|
||||
export const pauseRow = (row: AssetRow, rows: AssetRow[], setRows: Dispatch<AssetRow[]>) => {
|
||||
if (row.status === ListingStatus.PENDING || row.status === ListingStatus.DEFINED)
|
||||
updateStatus({
|
||||
listing: row,
|
||||
newStatus: ListingStatus.PAUSED,
|
||||
rows,
|
||||
setRows,
|
||||
})
|
||||
}
|
||||
|
||||
export const resetRow = (row: AssetRow, rows: AssetRow[], setRows: Dispatch<AssetRow[]>) => {
|
||||
if (
|
||||
row.status === ListingStatus.PAUSED ||
|
||||
row.status === ListingStatus.FAILED ||
|
||||
row.status === ListingStatus.REJECTED
|
||||
)
|
||||
updateStatus({
|
||||
listing: row,
|
||||
newStatus: ListingStatus.DEFINED,
|
||||
rows,
|
||||
setRows,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -240,21 +240,36 @@ export const RarityVerifiedIcon = () => (
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const EditPriceIcon = (props: SVGProps) => (
|
||||
<svg {...props} width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12.4713 5.06496L13.2161 4.28041C13.5935 3.88317 13.6233 3.33696 13.2459 2.95958L12.9877 2.69144C12.65 2.35378 12.084 2.40344 11.7165 2.77089L10.9419 3.52565L12.4713 5.06496ZM3.10986 13.2347L5.14573 12.3806L11.7463 5.78L10.2169 4.26055L3.61635 10.8711L2.72255 12.8374C2.62324 13.0658 2.88145 13.324 3.10986 13.2347Z"
|
||||
fill="#70757A"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const AttachPriceIcon = (props: SVGProps) => (
|
||||
<svg {...props} width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M7.76353 9.88671L8.53195 9.10825C7.93931 9.05803 7.51242 8.86216 7.20605 8.5558C6.35728 7.70702 6.35728 6.50669 7.20103 5.66796L8.86844 3.99553C9.71722 3.15178 10.9125 3.14676 11.7613 3.99553C12.6151 4.84932 12.6051 6.04464 11.7663 6.88839L10.9125 7.73716C11.0732 8.10881 11.1285 8.56082 11.0381 8.95256L12.4745 7.5212C13.71 6.29073 13.715 4.53292 12.4694 3.28738C11.2189 2.03682 9.47112 2.04687 8.23563 3.28236L6.48786 5.03013C5.25237 6.26562 5.24735 8.01841 6.49289 9.26394C6.78418 9.56026 7.18597 9.78124 7.76353 9.88671ZM8.23061 5.64285L7.46219 6.42131C8.05483 6.47655 8.48172 6.6674 8.78809 6.97376C9.64188 7.82254 9.63686 9.02287 8.79311 9.86662L7.1257 11.534C6.27693 12.3828 5.08161 12.3828 4.23786 11.534C3.38407 10.6802 3.38909 9.48995 4.23284 8.6462L5.08161 7.7924C4.9209 7.42577 4.87068 6.97376 4.95605 6.577L3.51967 8.01339C2.28418 9.24385 2.27916 10.9966 3.52469 12.2422C4.77525 13.4927 6.52302 13.4827 7.75851 12.2522L9.50628 10.4994C10.7418 9.26394 10.7468 7.51115 9.50126 6.26562C9.20996 5.97432 8.8132 5.75334 8.23061 5.64285Z"
|
||||
fill="#4673FA"
|
||||
/>
|
||||
export const BrokenLinkIcon = (props: SVGProps) => (
|
||||
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<g clipPath="url(#clip0_79_4612)">
|
||||
<path
|
||||
d="M14.4344 11.3181L16.9344 8.81813C17.6934 8.03229 18.1133 6.97978 18.1039 5.8873C18.0944 4.79481 17.6562 3.74976 16.8836 2.97722C16.1111 2.20469 15.066 1.76649 13.9735 1.75699C12.8811 1.7475 11.8286 2.16748 11.0427 2.92647L9.60938 4.35147"
|
||||
stroke="#98A1C0"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M5.20088 8.75098L2.70088 11.251C1.94189 12.0368 1.52191 13.0893 1.53141 14.1818C1.5409 15.2743 1.9791 16.3194 2.75164 17.0919C3.52417 17.8644 4.56922 18.3026 5.66171 18.3121C6.7542 18.3216 7.80671 17.9016 8.59255 17.1426L10.0175 15.7176"
|
||||
stroke="#98A1C0"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M5 3.24316L14.7368 16.6952"
|
||||
stroke="#98A1C0"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_79_4612">
|
||||
<rect width="20" height="20" fill="white" transform="translate(0.128906 0.0341797)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
)
|
||||
|
||||
@@ -289,30 +304,6 @@ export const ClockIcon = () => (
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const LoadingIcon = (props: SVGProps) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
width="100px"
|
||||
height="100px"
|
||||
viewBox="0 0 100 100"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
{...props}
|
||||
>
|
||||
<circle cx="50" cy="50" fill="none" strokeWidth="10" r="35" strokeDasharray="164.93361431346415 56.97787143782138">
|
||||
<animateTransform
|
||||
attributeName="transform"
|
||||
type="rotate"
|
||||
repeatCount="indefinite"
|
||||
dur="1s"
|
||||
values="0 50 50;360 50 50"
|
||||
keyTimes="0;1"
|
||||
{...props}
|
||||
></animateTransform>
|
||||
</circle>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const ApprovedCheckmarkIcon = (props: SVGProps) => (
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
@@ -322,25 +313,6 @@ export const ApprovedCheckmarkIcon = (props: SVGProps) => (
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const HazardIcon = () => (
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="8.57227" y="6.66669" width="2.85714" height="8.57143" fill="white" />
|
||||
<path
|
||||
d="M5.14158 15.7143H14.8489C15.8017 15.7143 16.4294 15.0318 16.4294 14.1977C16.4294 13.9377 16.3509 13.6885 16.2052 13.4502L11.3516 5.05483C11.0489 4.53486 10.5221 4.28571 9.99523 4.28571C9.46839 4.28571 8.93034 4.53486 8.6389 5.05483L3.78524 13.4502C3.63952 13.6885 3.57227 13.9377 3.57227 14.1977C3.57227 15.0318 4.18878 15.7143 5.14158 15.7143ZM9.99523 11.4245C9.56928 11.4245 9.25542 11.1428 9.24421 10.7312L9.15453 7.71969C9.14332 7.24305 9.49081 6.90724 9.99523 6.90724C10.5109 6.90724 10.8584 7.23222 10.8471 7.71969L10.7575 10.7312C10.7351 11.1428 10.4324 11.4245 9.99523 11.4245ZM9.99523 14.0677C9.43477 14.0677 8.98639 13.6452 8.98639 13.1036C8.98639 12.5728 9.43477 12.1503 9.99523 12.1503C10.5669 12.1503 11.0153 12.5836 11.0153 13.1036C11.0041 13.6452 10.5669 14.0677 9.99523 14.0677Z"
|
||||
fill="#F95E14"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const FailedListingIcon = (props: SVGProps) => (
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M9.9933 16.2444C13.5529 16.2444 16.4909 13.3064 16.4909 9.75307C16.4909 6.19978 13.5466 3.26172 9.98703 3.26172C6.43373 3.26172 3.50195 6.19978 3.50195 9.75307C3.50195 13.3064 6.44001 16.2444 9.9933 16.2444ZM8.12877 12.3207C7.78976 12.3207 7.62653 12.1324 7.62653 11.8624V7.63742C7.62653 7.36747 7.78976 7.17913 8.12877 7.17913H8.80678C9.14579 7.17913 9.30901 7.36747 9.30901 7.63742V11.8624C9.30901 12.1324 9.14579 12.3207 8.80678 12.3207H8.12877ZM11.1798 12.3207C10.8471 12.3207 10.6776 12.1324 10.6776 11.8624V7.63742C10.6776 7.36747 10.8471 7.17913 11.1798 7.17913H11.8641C12.1906 7.17913 12.3538 7.36747 12.3538 7.63742V11.8624C12.3538 12.1324 12.1906 12.3207 11.8641 12.3207H11.1798Z"
|
||||
fill={themeVars.colors.textSecondary}
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const FilterIcon = (props: SVGProps) => (
|
||||
<svg width="20" height="20" viewBox="1 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
|
||||
@@ -16,6 +16,6 @@ export const overlay = style([
|
||||
{
|
||||
opacity: 0.72,
|
||||
overflow: 'hidden',
|
||||
zIndex: Z_INDEX.modalBackdrop + 1,
|
||||
zIndex: Z_INDEX.modalBackdrop - 2,
|
||||
},
|
||||
])
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { sendAnalyticsEvent, useTrace } from '@uniswap/analytics'
|
||||
import { InterfaceModalName, NFTEventName } from '@uniswap/analytics-events'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import Column from 'components/Column'
|
||||
import Row from 'components/Row'
|
||||
import { SMALL_MEDIA_BREAKPOINT } from 'components/Tokens/constants'
|
||||
import { NftListV2Variant, useNftListV2Flag } from 'featureFlags/flags/nftListV2'
|
||||
import { ListingButton } from 'nft/components/bag/profile/ListingButton'
|
||||
import { approveCollectionRow, getListingState, getTotalEthValue, verifyStatus } from 'nft/components/bag/profile/utils'
|
||||
import { useBag, useIsMobile, useNFTList, useProfilePageState, useSellAsset } from 'nft/hooks'
|
||||
import { ListingButton } from 'nft/components/profile/list/ListingButton'
|
||||
import { useIsMobile, useNFTList, useProfilePageState, useSellAsset } from 'nft/hooks'
|
||||
import { LIST_PAGE_MARGIN, LIST_PAGE_MARGIN_MOBILE } from 'nft/pages/profile/shared'
|
||||
import { looksRareNonceFetcher } from 'nft/queries'
|
||||
import { ListingStatus, ProfilePageStateType } from 'nft/types'
|
||||
@@ -16,7 +14,7 @@ import { fetchPrice, formatEth, formatUsdPrice } from 'nft/utils'
|
||||
import { ListingMarkets } from 'nft/utils/listNfts'
|
||||
import { useEffect, useMemo, useReducer, useState } from 'react'
|
||||
import { ArrowLeft } from 'react-feather'
|
||||
import styled, { css } from 'styled-components/macro'
|
||||
import styled from 'styled-components/macro'
|
||||
import { BREAKPOINTS, ThemedText } from 'theme'
|
||||
import { Z_INDEX } from 'theme/zIndex'
|
||||
import shallow from 'zustand/shallow'
|
||||
@@ -81,20 +79,11 @@ const ButtonsWrapper = styled(Row)`
|
||||
width: min-content;
|
||||
`
|
||||
|
||||
const MarketWrap = styled.section<{ isNftListV2: boolean }>`
|
||||
const MarketWrap = styled.section`
|
||||
gap: 48px;
|
||||
margin: 0px auto;
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
${({ isNftListV2 }) => !isNftListV2 && v1Padding}
|
||||
`
|
||||
|
||||
const v1Padding = css`
|
||||
padding: 0px 16px;
|
||||
|
||||
@media screen and (min-width: ${SMALL_MEDIA_BREAKPOINT}) {
|
||||
padding: 0px 44px;
|
||||
}
|
||||
`
|
||||
|
||||
const ListingHeaderRow = styled(Row)`
|
||||
@@ -112,15 +101,6 @@ const GridWrapper = styled.div`
|
||||
margin-bottom: 48px;
|
||||
`
|
||||
|
||||
const MobileListButtonWrapper = styled.div`
|
||||
display: flex;
|
||||
margin: 14px 16px 32px 16px;
|
||||
|
||||
@media screen and (min-width: ${SMALL_MEDIA_BREAKPOINT}) {
|
||||
display: none;
|
||||
}
|
||||
`
|
||||
|
||||
const FloatingConfirmationBar = styled(Row)<{ issues: boolean }>`
|
||||
padding: 12px 12px 12px 32px;
|
||||
border: 1px solid;
|
||||
@@ -195,9 +175,7 @@ const EthValueWrapper = styled.span<{ totalEthListingValue: boolean }>`
|
||||
export const ListPage = () => {
|
||||
const { setProfilePageState: setSellPageState } = useProfilePageState()
|
||||
const { provider } = useWeb3React()
|
||||
const toggleBag = useBag((s) => s.toggleBag)
|
||||
const isMobile = useIsMobile()
|
||||
const isNftListV2 = useNftListV2Flag() === NftListV2Variant.Enabled
|
||||
const trace = useTrace({ modal: InterfaceModalName.NFT_LISTING })
|
||||
const { setGlobalMarketplaces, sellAssets, issues } = useSellAsset(
|
||||
({ setGlobalMarketplaces, sellAssets, issues }) => ({
|
||||
@@ -234,7 +212,6 @@ export const ListPage = () => {
|
||||
)
|
||||
|
||||
const totalEthListingValue = useMemo(() => getTotalEthValue(sellAssets), [sellAssets])
|
||||
const anyListingsMissingPrice = useMemo(() => !!listings.find((listing) => !listing.price), [listings])
|
||||
const [showListModal, toggleShowListModal] = useReducer((s) => !s, false)
|
||||
const [selectedMarkets, setSelectedMarkets] = useState([ListingMarkets[0]]) // default marketplace: x2y2
|
||||
const [ethPriceInUSD, setEthPriceInUSD] = useState(0)
|
||||
@@ -291,7 +268,7 @@ export const ListPage = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleV2Click = () => {
|
||||
const showModalAndStartListing = () => {
|
||||
toggleShowListModal()
|
||||
startListingFlow()
|
||||
}
|
||||
@@ -308,7 +285,7 @@ export const ListPage = () => {
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<MarketWrap isNftListV2={isNftListV2}>
|
||||
<MarketWrap>
|
||||
<ListingHeader>
|
||||
<Row>
|
||||
<ArrowContainer>
|
||||
@@ -332,39 +309,24 @@ export const ListPage = () => {
|
||||
<NFTListingsGrid selectedMarkets={selectedMarkets} />
|
||||
</GridWrapper>
|
||||
</MarketWrap>
|
||||
{isNftListV2 && (
|
||||
<>
|
||||
<FloatingConfirmationBar issues={!!issues}>
|
||||
{BannerText}
|
||||
<ProceedsAndButtonWrapper>
|
||||
<ProceedsWrapper>
|
||||
<EthValueWrapper totalEthListingValue={!!totalEthListingValue}>
|
||||
{totalEthListingValue > 0 ? formatEth(totalEthListingValue) : '-'} ETH
|
||||
</EthValueWrapper>
|
||||
{!!totalEthListingValue && !!ethPriceInUSD && (
|
||||
<UsdValue>{formatUsdPrice(totalEthListingValue * ethPriceInUSD)}</UsdValue>
|
||||
)}
|
||||
</ProceedsWrapper>
|
||||
<ListingButton
|
||||
onClick={handleV2Click}
|
||||
buttonText={anyListingsMissingPrice && !isMobile ? t`Set prices to continue` : t`Start listing`}
|
||||
showWarningOverride={true}
|
||||
/>
|
||||
</ProceedsAndButtonWrapper>
|
||||
</FloatingConfirmationBar>
|
||||
<Overlay />
|
||||
</>
|
||||
)}
|
||||
{!isNftListV2 && (
|
||||
<MobileListButtonWrapper>
|
||||
<ListingButton onClick={toggleBag} buttonText="Continue listing" />
|
||||
</MobileListButtonWrapper>
|
||||
)}
|
||||
{isNftListV2 && showListModal && (
|
||||
<>
|
||||
<ListModal overlayClick={toggleShowListModal} />
|
||||
</>
|
||||
)}
|
||||
|
||||
<FloatingConfirmationBar issues={!!issues}>
|
||||
{BannerText}
|
||||
<ProceedsAndButtonWrapper>
|
||||
<ProceedsWrapper>
|
||||
<EthValueWrapper totalEthListingValue={!!totalEthListingValue}>
|
||||
{totalEthListingValue > 0 ? formatEth(totalEthListingValue) : '-'} ETH
|
||||
</EthValueWrapper>
|
||||
{!!totalEthListingValue && !!ethPriceInUSD && (
|
||||
<UsdValue>{formatUsdPrice(totalEthListingValue * ethPriceInUSD)}</UsdValue>
|
||||
)}
|
||||
</ProceedsWrapper>
|
||||
<ListingButton onClick={showModalAndStartListing} />
|
||||
</ProceedsAndButtonWrapper>
|
||||
</FloatingConfirmationBar>
|
||||
<Overlay />
|
||||
|
||||
{showListModal && <ListModal overlayClick={toggleShowListModal} />}
|
||||
</Column>
|
||||
)
|
||||
}
|
||||
|
||||
144
src/nft/components/profile/list/ListingButton.tsx
Normal file
144
src/nft/components/profile/list/ListingButton.tsx
Normal file
@@ -0,0 +1,144 @@
|
||||
import { Plural, t, Trans } from '@lingui/macro'
|
||||
import { BaseButton } from 'components/Button'
|
||||
import ms from 'ms.macro'
|
||||
import { BelowFloorWarningModal } from 'nft/components/profile/list/Modal/BelowFloorWarningModal'
|
||||
import { useIsMobile, useNFTList, useSellAsset } from 'nft/hooks'
|
||||
import { Listing, ListingStatus, WalletAsset } from 'nft/types'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
import { BREAKPOINTS } from 'theme'
|
||||
import shallow from 'zustand/shallow'
|
||||
|
||||
import { getListings } from '../../bag/profile/utils'
|
||||
|
||||
const BELOW_FLOOR_PRICE_THRESHOLD = 0.8
|
||||
|
||||
const StyledListingButton = styled(BaseButton)<{ showResolveIssues: boolean; missingPrices: boolean }>`
|
||||
background: ${({ showResolveIssues, theme }) => (showResolveIssues ? theme.accentFailure : theme.accentAction)};
|
||||
color: ${({ theme }) => theme.accentTextLightPrimary};
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
padding: 16px;
|
||||
border-radius: 12px;
|
||||
width: min-content;
|
||||
border: none;
|
||||
cursor: ${({ missingPrices }) => (missingPrices ? 'auto' : 'pointer')};
|
||||
opacity: ${({ showResolveIssues, missingPrices }) => !showResolveIssues && missingPrices && '0.3'};
|
||||
|
||||
@media screen and (max-width: ${BREAKPOINTS.sm}px) {
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
`
|
||||
|
||||
export const ListingButton = ({ onClick }: { onClick: () => void }) => {
|
||||
const { sellAssets, showResolveIssues, toggleShowResolveIssues, issues, setIssues } = useSellAsset(
|
||||
({ sellAssets, showResolveIssues, toggleShowResolveIssues, issues, setIssues }) => ({
|
||||
sellAssets,
|
||||
showResolveIssues,
|
||||
toggleShowResolveIssues,
|
||||
issues,
|
||||
setIssues,
|
||||
}),
|
||||
shallow
|
||||
)
|
||||
const { setListingStatus, setListings, setCollectionsRequiringApproval } = useNFTList(
|
||||
({ setListingStatus, setListings, setCollectionsRequiringApproval }) => ({
|
||||
setListingStatus,
|
||||
setListings,
|
||||
setCollectionsRequiringApproval,
|
||||
}),
|
||||
shallow
|
||||
)
|
||||
const [showWarning, setShowWarning] = useState(false)
|
||||
const isMobile = useIsMobile()
|
||||
|
||||
// instantiate listings and collections to approve when user's modify input data
|
||||
useEffect(() => {
|
||||
const [newCollectionsToApprove, newListings] = getListings(sellAssets)
|
||||
setListings(newListings)
|
||||
setCollectionsRequiringApproval(newCollectionsToApprove)
|
||||
setListingStatus(ListingStatus.DEFINED)
|
||||
}, [sellAssets, setCollectionsRequiringApproval, setListingStatus, setListings])
|
||||
|
||||
// Find issues with item listing data
|
||||
const [listingsMissingPrice, listingsBelowFloor] = useMemo(() => {
|
||||
const missingExpiration = sellAssets.some((asset) => {
|
||||
return (
|
||||
asset.expirationTime != null &&
|
||||
(isNaN(asset.expirationTime) || asset.expirationTime * 1000 - Date.now() < ms`60 seconds`)
|
||||
)
|
||||
})
|
||||
const overMaxExpiration = sellAssets.some((asset) => {
|
||||
return asset.expirationTime != null && asset.expirationTime * 1000 - Date.now() > ms`180 days`
|
||||
})
|
||||
|
||||
const listingsMissingPrice: [WalletAsset, Listing][] = []
|
||||
const listingsBelowFloor: [WalletAsset, Listing][] = []
|
||||
const listingsAboveSellOrderFloor: [WalletAsset, Listing][] = []
|
||||
const invalidPrices: [WalletAsset, Listing][] = []
|
||||
for (const asset of sellAssets) {
|
||||
if (asset.newListings) {
|
||||
for (const listing of asset.newListings) {
|
||||
if (!listing.price) listingsMissingPrice.push([asset, listing])
|
||||
else if (isNaN(listing.price) || listing.price < 0) invalidPrices.push([asset, listing])
|
||||
else if (
|
||||
listing.price < (asset?.floorPrice ?? 0) * BELOW_FLOOR_PRICE_THRESHOLD &&
|
||||
!listing.overrideFloorPrice
|
||||
)
|
||||
listingsBelowFloor.push([asset, listing])
|
||||
else if (asset.floor_sell_order_price && listing.price >= asset.floor_sell_order_price)
|
||||
listingsAboveSellOrderFloor.push([asset, listing])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set number of issues
|
||||
const foundIssues =
|
||||
Number(missingExpiration) +
|
||||
Number(overMaxExpiration) +
|
||||
listingsMissingPrice.length +
|
||||
listingsAboveSellOrderFloor.length
|
||||
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)
|
||||
toggleShowResolveIssues()
|
||||
|
||||
return [listingsMissingPrice, listingsBelowFloor]
|
||||
}, [sellAssets, setIssues, showResolveIssues, toggleShowResolveIssues])
|
||||
|
||||
const warningWrappedClick = () => {
|
||||
if (issues) !showResolveIssues && toggleShowResolveIssues()
|
||||
else if (listingsBelowFloor.length) setShowWarning(true)
|
||||
else onClick()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledListingButton
|
||||
onClick={warningWrappedClick}
|
||||
missingPrices={!!listingsMissingPrice.length}
|
||||
showResolveIssues={showResolveIssues}
|
||||
>
|
||||
{showResolveIssues ? (
|
||||
<Plural value={issues !== 1 ? 2 : 1} _1="Resolve issue" other={t`Resolve ${issues} issues`} />
|
||||
) : listingsMissingPrice.length && !isMobile ? (
|
||||
<Trans>Set prices to continue</Trans>
|
||||
) : (
|
||||
<Trans>Start listing</Trans>
|
||||
)}
|
||||
</StyledListingButton>
|
||||
|
||||
{showWarning && (
|
||||
<BelowFloorWarningModal
|
||||
listingsBelowFloor={listingsBelowFloor}
|
||||
closeModal={() => setShowWarning(false)}
|
||||
startListing={onClick}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -136,13 +136,18 @@ export const MarketplaceRow = ({
|
||||
toggleExpandMarketplaceRows,
|
||||
rowHovered,
|
||||
}: MarketplaceRowProps) => {
|
||||
const [listPrice, setListPrice] = useState<number>()
|
||||
const [globalOverride, setGlobalOverride] = useState(false)
|
||||
const showGlobalPrice = globalPriceMethod === SetPriceMethod.SAME_PRICE && !globalOverride && globalPrice
|
||||
const setAssetListPrice = useSellAsset((state) => state.setAssetListPrice)
|
||||
const removeAssetMarketplace = useSellAsset((state) => state.removeAssetMarketplace)
|
||||
const [marketIconHovered, toggleMarketIconHovered] = useReducer((s) => !s, false)
|
||||
const [marketRowHovered, toggleMarketRowHovered] = useReducer((s) => !s, false)
|
||||
const [listPrice, setListPrice] = useState<number | undefined>(
|
||||
() =>
|
||||
asset.newListings?.find((listing) =>
|
||||
expandMarketplaceRows ? listing.marketplace.name === selectedMarkets?.[0].name : !!listing.price
|
||||
)?.price
|
||||
)
|
||||
const [globalOverride, setGlobalOverride] = useState(false)
|
||||
const showGlobalPrice = globalPriceMethod === SetPriceMethod.SAME_PRICE && !globalOverride && globalPrice
|
||||
|
||||
const price = showGlobalPrice ? globalPrice : listPrice
|
||||
|
||||
@@ -198,7 +203,7 @@ export const MarketplaceRow = ({
|
||||
if (!listPrice) setListPrice(globalPrice)
|
||||
price = listPrice ? listPrice : globalPrice
|
||||
} else {
|
||||
price = globalPrice
|
||||
price = listPrice
|
||||
}
|
||||
if (selectedMarkets.length) for (const marketplace of selectedMarkets) setAssetListPrice(asset, price, marketplace)
|
||||
else setAssetListPrice(asset, price)
|
||||
@@ -228,14 +233,14 @@ export const MarketplaceRow = ({
|
||||
return (
|
||||
<Row onMouseEnter={toggleMarketRowHovered} onMouseLeave={toggleMarketRowHovered}>
|
||||
<FloorPriceInfo>
|
||||
<ThemedText.BodySmall color="textSecondary" lineHeight="20px">
|
||||
<ThemedText.BodyPrimary color="textSecondary" lineHeight="24px">
|
||||
{asset.floorPrice ? `${asset.floorPrice.toFixed(3)} ETH` : '-'}
|
||||
</ThemedText.BodySmall>
|
||||
</ThemedText.BodyPrimary>
|
||||
</FloorPriceInfo>
|
||||
<LastPriceInfo>
|
||||
<ThemedText.BodySmall color="textSecondary" lineHeight="20px">
|
||||
<ThemedText.BodyPrimary color="textSecondary" lineHeight="24px">
|
||||
{asset.lastPrice ? `${asset.lastPrice.toFixed(3)} ETH` : '-'}
|
||||
</ThemedText.BodySmall>
|
||||
</ThemedText.BodyPrimary>
|
||||
</LastPriceInfo>
|
||||
|
||||
<Row flex="2">
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Overlay } from 'nft/components/modals/Overlay'
|
||||
import { useNFTList, useSellAsset } from 'nft/hooks'
|
||||
import { ListingStatus } from 'nft/types'
|
||||
import { fetchPrice } from 'nft/utils'
|
||||
import { useEffect, useMemo, useReducer, useState } from 'react'
|
||||
import { useCallback, useEffect, useMemo, useReducer, useState } from 'react'
|
||||
import { X } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import { BREAKPOINTS, ThemedText } from 'theme'
|
||||
@@ -112,24 +112,28 @@ export const ListModal = ({ overlayClick }: { overlayClick: () => void }) => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [allCollectionsApproved])
|
||||
|
||||
const closeModalOnClick = useCallback(() => {
|
||||
listingStatus === ListingStatus.APPROVED ? window.location.reload() : overlayClick()
|
||||
}, [listingStatus, overlayClick])
|
||||
|
||||
// In the case that a user removes all listings via retry logic, close modal
|
||||
useEffect(() => {
|
||||
!listings.length && overlayClick()
|
||||
}, [listings, overlayClick])
|
||||
!listings.length && closeModalOnClick()
|
||||
}, [listings, closeModalOnClick])
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Trace modal={InterfaceModalName.NFT_LISTING}>
|
||||
<ListModalWrapper>
|
||||
{listingStatus === ListingStatus.APPROVED ? (
|
||||
<SuccessScreen overlayClick={overlayClick} />
|
||||
<SuccessScreen overlayClick={closeModalOnClick} />
|
||||
) : (
|
||||
<>
|
||||
<TitleRow>
|
||||
<ThemedText.HeadlineSmall lineHeight="28px">
|
||||
<Trans>List NFTs</Trans>
|
||||
</ThemedText.HeadlineSmall>
|
||||
<X size={24} cursor="pointer" onClick={overlayClick} />
|
||||
<X size={24} cursor="pointer" onClick={closeModalOnClick} />
|
||||
</TitleRow>
|
||||
<ListModalSection
|
||||
sectionType={Section.APPROVE}
|
||||
@@ -147,7 +151,7 @@ export const ListModal = ({ overlayClick }: { overlayClick: () => void }) => {
|
||||
)}
|
||||
</ListModalWrapper>
|
||||
</Trace>
|
||||
<Overlay onClick={overlayClick} />
|
||||
<Overlay onClick={closeModalOnClick} />
|
||||
</Portal>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import { opacify } from 'theme/utils'
|
||||
import { MarketplaceRow } from './MarketplaceRow'
|
||||
import { SetPriceMethod } from './NFTListingsGrid'
|
||||
|
||||
const IMAGE_THUMBNAIL_SIZE = 60
|
||||
|
||||
const NFTListRowWrapper = styled(Row)`
|
||||
padding: 24px 0px;
|
||||
align-items: center;
|
||||
@@ -23,8 +25,8 @@ const NFTListRowWrapper = styled(Row)`
|
||||
`
|
||||
|
||||
const RemoveIconContainer = styled.div`
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
width: ${IMAGE_THUMBNAIL_SIZE}px;
|
||||
height: ${IMAGE_THUMBNAIL_SIZE}px;
|
||||
padding-left: 12px;
|
||||
align-self: flex-start;
|
||||
align-items: center;
|
||||
@@ -51,8 +53,8 @@ const NFTInfoWrapper = styled(Row)`
|
||||
`
|
||||
|
||||
const NFTImage = styled.img`
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
width: ${IMAGE_THUMBNAIL_SIZE}px;
|
||||
height: ${IMAGE_THUMBNAIL_SIZE}px;
|
||||
border-radius: 8px;
|
||||
margin-right: 8px;
|
||||
`
|
||||
@@ -85,6 +87,7 @@ const MarketPlaceRowWrapper = styled(Column)`
|
||||
gap: 24px;
|
||||
flex: 1.5;
|
||||
margin-right: 12px;
|
||||
padding: 6px 0px;
|
||||
|
||||
@media screen and (min-width: ${BREAKPOINTS.md}px) {
|
||||
flex: 2;
|
||||
|
||||
@@ -28,7 +28,7 @@ const TableHeader = styled.div`
|
||||
line-height: 20px;
|
||||
|
||||
@media screen and (min-width: ${BREAKPOINTS.sm}px) {
|
||||
margin-left: 48px;
|
||||
padding-left: 48px;
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import Column from 'components/Column'
|
||||
import Row from 'components/Row'
|
||||
import { AttachPriceIcon, EditPriceIcon } from 'nft/components/icons'
|
||||
import { BrokenLinkIcon } from 'nft/components/icons'
|
||||
import { NumericInput } from 'nft/components/layout/Input'
|
||||
import { body } from 'nft/css/common.css'
|
||||
import { useSellAsset } from 'nft/hooks'
|
||||
import { ListingWarning, WalletAsset } from 'nft/types'
|
||||
import { formatEth } from 'nft/utils/currency'
|
||||
import { Dispatch, FormEvent, useEffect, useRef, useState } from 'react'
|
||||
import { AlertTriangle } from 'react-feather'
|
||||
import { AlertTriangle, Link } from 'react-feather'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { BREAKPOINTS } from 'theme'
|
||||
import { colors } from 'theme/colors'
|
||||
@@ -19,7 +19,7 @@ const PriceTextInputWrapper = styled(Column)`
|
||||
`
|
||||
|
||||
const InputWrapper = styled(Row)<{ borderColor: string }>`
|
||||
height: 44px;
|
||||
height: 48px;
|
||||
color: ${({ theme }) => theme.textTertiary};
|
||||
padding: 12px;
|
||||
border: 2px solid;
|
||||
@@ -34,12 +34,17 @@ const CurrencyWrapper = styled.div<{ listPrice: number | undefined }>`
|
||||
`
|
||||
|
||||
const GlobalPriceIcon = styled.div`
|
||||
display: block;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -4px;
|
||||
bottom: 32px;
|
||||
right: -10px;
|
||||
background-color: ${({ theme }) => theme.backgroundSurface};
|
||||
border-radius: 50%;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
`
|
||||
|
||||
const WarningRow = styled(Row)`
|
||||
@@ -104,7 +109,6 @@ export const PriceTextInput = ({
|
||||
warning,
|
||||
asset,
|
||||
}: PriceTextInputProps) => {
|
||||
const [focused, setFocused] = useState(false)
|
||||
const [warningType, setWarningType] = useState(WarningType.NONE)
|
||||
const removeMarketplaceWarning = useSellAsset((state) => state.removeMarketplaceWarning)
|
||||
const removeSellAsset = useSellAsset((state) => state.removeSellAsset)
|
||||
@@ -128,7 +132,7 @@ export const PriceTextInput = ({
|
||||
const warningColor =
|
||||
showResolveIssues && !listPrice
|
||||
? colors.red400
|
||||
: warningType !== WarningType.NONE && !focused
|
||||
: warningType !== WarningType.NONE
|
||||
? (warningType === WarningType.BELOW_FLOOR && percentBelowFloor >= 20) ||
|
||||
warningType === WarningType.ALREADY_LISTED
|
||||
? colors.red400
|
||||
@@ -151,10 +155,6 @@ export const PriceTextInput = ({
|
||||
placeholder="0"
|
||||
backgroundColor="none"
|
||||
width={{ sm: '54', md: '68' }}
|
||||
onFocus={() => setFocused(true)}
|
||||
onBlur={() => {
|
||||
setFocused(false)
|
||||
}}
|
||||
ref={inputRef}
|
||||
onChange={(v: FormEvent<HTMLInputElement>) => {
|
||||
if (!listPrice && v.currentTarget.value.includes('.') && parseFloat(v.currentTarget.value) === 0) {
|
||||
@@ -167,7 +167,7 @@ export const PriceTextInput = ({
|
||||
<CurrencyWrapper listPrice={listPrice}> ETH</CurrencyWrapper>
|
||||
{(isGlobalPrice || globalOverride) && (
|
||||
<GlobalPriceIcon onClick={() => setGlobalOverride(!globalOverride)}>
|
||||
{globalOverride ? <AttachPriceIcon /> : <EditPriceIcon />}
|
||||
{globalOverride ? <BrokenLinkIcon /> : <Link size={20} color={warningColor} />}
|
||||
</GlobalPriceIcon>
|
||||
)}
|
||||
</InputWrapper>
|
||||
|
||||
@@ -138,7 +138,7 @@ export const ProfilePage = () => {
|
||||
borderRadius="12"
|
||||
paddingX="16"
|
||||
paddingY="12"
|
||||
background="backgroundModule"
|
||||
background="backgroundSurface"
|
||||
borderStyle="solid"
|
||||
borderColor="backgroundOutline"
|
||||
borderWidth="1px"
|
||||
|
||||
@@ -18,27 +18,10 @@ export const subheadSmall = sprinkles({ fontWeight: 'medium', fontSize: '14', li
|
||||
export const body = sprinkles({ fontWeight: 'normal', fontSize: '16', lineHeight: '24' })
|
||||
export const bodySmall = sprinkles({ fontWeight: 'normal', fontSize: '14', lineHeight: '20' })
|
||||
export const caption = sprinkles({ fontWeight: 'normal', fontSize: '12', lineHeight: '16' })
|
||||
export const badge = sprinkles({ fontWeight: 'semibold', fontSize: '10', lineHeight: '12' })
|
||||
|
||||
export const buttonTextMedium = sprinkles({ fontWeight: 'semibold', fontSize: '16', lineHeight: '20' })
|
||||
export const buttonTextSmall = sprinkles({ fontWeight: 'semibold', fontSize: '14', lineHeight: '16' })
|
||||
|
||||
export const commonButtonStyles = style([
|
||||
sprinkles({
|
||||
borderRadius: '12',
|
||||
transition: '250',
|
||||
}),
|
||||
{
|
||||
border: 'none',
|
||||
':hover': {
|
||||
cursor: 'pointer',
|
||||
},
|
||||
':disabled': {
|
||||
cursor: 'auto',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const magicalGradient = style({
|
||||
selectors: {
|
||||
'&::before': {
|
||||
|
||||
50
src/nft/hooks/usePriceImpact.ts
Normal file
50
src/nft/hooks/usePriceImpact.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { useMemo } from 'react'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import { useTheme } from 'styled-components/macro'
|
||||
import { computeRealizedPriceImpact, getPriceImpactWarning } from 'utils/prices'
|
||||
|
||||
export interface PriceImpact {
|
||||
priceImpactSeverity: PriceImpactSeverity
|
||||
displayPercentage(): string
|
||||
}
|
||||
|
||||
interface PriceImpactSeverity {
|
||||
type: 'warning' | 'error'
|
||||
color: string
|
||||
}
|
||||
|
||||
export function usePriceImpact(trade?: InterfaceTrade<Currency, Currency, TradeType>): PriceImpact | undefined {
|
||||
const theme = useTheme()
|
||||
|
||||
return useMemo(() => {
|
||||
const marketPriceImpact = trade ? computeRealizedPriceImpact(trade) : undefined
|
||||
const priceImpactWarning = marketPriceImpact ? getPriceImpactWarning(marketPriceImpact) : undefined
|
||||
const warningColor =
|
||||
priceImpactWarning === 'error'
|
||||
? theme.accentCritical
|
||||
: priceImpactWarning === 'warning'
|
||||
? theme.accentWarning
|
||||
: undefined
|
||||
|
||||
return marketPriceImpact && priceImpactWarning && warningColor
|
||||
? {
|
||||
priceImpactSeverity: {
|
||||
type: priceImpactWarning,
|
||||
color: warningColor,
|
||||
},
|
||||
displayPercentage: () => toHumanReadablePercent(marketPriceImpact),
|
||||
}
|
||||
: undefined
|
||||
}, [theme.accentCritical, theme.accentWarning, trade])
|
||||
}
|
||||
|
||||
function toHumanReadablePercent(priceImpact: Percent): string {
|
||||
const sign = priceImpact.lessThan(0) ? '+' : ''
|
||||
const exactFloat = (Number(priceImpact.numerator) / Number(priceImpact.denominator)) * 100
|
||||
if (exactFloat < 0.005) {
|
||||
return '0.00%'
|
||||
}
|
||||
const number = parseFloat(priceImpact.multiply(-1)?.toFixed(2))
|
||||
return `${sign}${number}%`
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import { CollectionPageSkeleton } from 'nft/components/collection/CollectionPage
|
||||
import { BagCloseIcon } from 'nft/components/icons'
|
||||
import { useBag, useCollectionFilters, useFiltersExpanded, useIsMobile } from 'nft/hooks'
|
||||
import * as styles from 'nft/pages/collection/index.css'
|
||||
import { blocklistedCollections } from 'nft/utils'
|
||||
import { Suspense, useEffect } from 'react'
|
||||
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
||||
import { animated, easings, useSpring } from 'react-spring'
|
||||
@@ -85,7 +86,7 @@ const FiltersContainer = styled.div<{ isMobile: boolean; isFiltersExpanded: bool
|
||||
width: ${({ isMobile }) => (isMobile ? '100%' : '0px')};
|
||||
height: ${({ isMobile, isFiltersExpanded }) => (isMobile && isFiltersExpanded ? '100%' : undefined)};
|
||||
background: ${({ theme, isMobile }) => (isMobile ? theme.backgroundBackdrop : undefined)};
|
||||
z-index: ${Z_INDEX.modalBackdrop};
|
||||
z-index: ${Z_INDEX.modalBackdrop - 3};
|
||||
overflow-y: ${({ isMobile }) => (isMobile ? 'scroll' : undefined)};
|
||||
|
||||
@media screen and (min-width: ${({ theme }) => theme.breakpoint.sm}px) {
|
||||
@@ -188,7 +189,7 @@ const Collection = () => {
|
||||
width: CollectionContainerWidthChange.to((x) => `calc(100% - ${x as number}px)`),
|
||||
}}
|
||||
>
|
||||
{contractAddress ? (
|
||||
{contractAddress && !blocklistedCollections.includes(contractAddress) ? (
|
||||
<>
|
||||
<BannerWrapper>
|
||||
<Banner
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Trace } from '@uniswap/analytics'
|
||||
import { InterfacePageName } from '@uniswap/analytics-events'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { ButtonPrimary } from 'components/Button'
|
||||
import { NftListV2Variant, useNftListV2Flag } from 'featureFlags/flags/nftListV2'
|
||||
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'
|
||||
@@ -26,17 +26,17 @@ const ProfilePageWrapper = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
const LoadedAccountPage = styled.div<{ cartExpanded: boolean; isOnV2ListPage: boolean }>`
|
||||
const LoadedAccountPage = styled.div<{ cartExpanded: boolean; isListingNfts: boolean }>`
|
||||
width: calc(
|
||||
100% -
|
||||
${({ cartExpanded, isOnV2ListPage }) =>
|
||||
isOnV2ListPage ? LIST_PAGE_MARGIN * 2 : cartExpanded ? XXXL_BAG_WIDTH : 0}px
|
||||
${({ cartExpanded, isListingNfts }) =>
|
||||
isListingNfts ? LIST_PAGE_MARGIN * 2 : cartExpanded ? XXXL_BAG_WIDTH : 0}px
|
||||
);
|
||||
margin: 0px ${({ isOnV2ListPage }) => (isOnV2ListPage ? LIST_PAGE_MARGIN : 0)}px;
|
||||
margin: 0px ${({ isListingNfts }) => (isListingNfts ? LIST_PAGE_MARGIN : 0)}px;
|
||||
|
||||
@media screen and (max-width: ${BREAKPOINTS.sm}px) {
|
||||
width: calc(100% - ${({ isOnV2ListPage }) => (isOnV2ListPage ? LIST_PAGE_MARGIN_MOBILE * 2 : 0)}px);
|
||||
margin: 0px ${({ isOnV2ListPage }) => (isOnV2ListPage ? LIST_PAGE_MARGIN_MOBILE : 0)}px;
|
||||
width: calc(100% - ${({ isListingNfts }) => (isListingNfts ? LIST_PAGE_MARGIN_MOBILE * 2 : 0)}px);
|
||||
margin: 0px ${({ isListingNfts }) => (isListingNfts ? LIST_PAGE_MARGIN_MOBILE : 0)}px;
|
||||
}
|
||||
`
|
||||
|
||||
@@ -85,25 +85,23 @@ const ProfileContent = () => {
|
||||
}
|
||||
}, [account, resetSellAssets, setSellPageState, clearCollectionFilters])
|
||||
const cartExpanded = useBag((state) => state.bagExpanded)
|
||||
const isNftListV2 = useNftListV2Flag() === NftListV2Variant.Enabled
|
||||
const isListingNfts = sellPageState === ProfilePageStateType.LISTING
|
||||
const isOnV2ListPage = isNftListV2 && isListingNfts
|
||||
|
||||
return (
|
||||
<Trace page={InterfacePageName.NFT_PROFILE_PAGE} shouldLogImpression>
|
||||
<ProfilePageWrapper>
|
||||
{account ? (
|
||||
<LoadedAccountPage cartExpanded={cartExpanded} isOnV2ListPage={isOnV2ListPage}>
|
||||
<LoadedAccountPage cartExpanded={cartExpanded} isListingNfts={isListingNfts}>
|
||||
{!isListingNfts ? <ProfilePage /> : <ListPage />}
|
||||
</LoadedAccountPage>
|
||||
) : (
|
||||
<Center>
|
||||
<ThemedText.HeadlineMedium lineHeight="36px" color="textSecondary" fontWeight="600" marginBottom="24px">
|
||||
No items to display
|
||||
<Trans>No items to display</Trans>
|
||||
</ThemedText.HeadlineMedium>
|
||||
<ConnectWalletButton onClick={toggleWalletModal}>
|
||||
<ThemedText.SubHeader color="white" lineHeight="20px">
|
||||
Connect Wallet
|
||||
<Trans>Connect Wallet</Trans>
|
||||
</ThemedText.SubHeader>
|
||||
</ConnectWalletButton>
|
||||
</Center>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { isAddress } from '@ethersproject/address'
|
||||
import { blocklistedCollections } from 'nft/utils'
|
||||
|
||||
import { GenieCollection } from '../../types'
|
||||
|
||||
@@ -45,15 +46,17 @@ export const fetchSearchCollections = async (addressOrName: string, recursive =
|
||||
if (isName) {
|
||||
const data = await r.json()
|
||||
const formattedData = data?.data
|
||||
? data.data.map((collection: { stats: Record<string, unknown>; floorPrice: string }) => {
|
||||
return {
|
||||
...collection,
|
||||
stats: {
|
||||
...collection.stats,
|
||||
floor_price: collection.floorPrice,
|
||||
},
|
||||
}
|
||||
})
|
||||
? data.data
|
||||
.filter((collection: { address: string }) => !blocklistedCollections.includes(collection.address))
|
||||
.map((collection: { stats: Record<string, unknown>; floorPrice: string }) => {
|
||||
return {
|
||||
...collection,
|
||||
stats: {
|
||||
...collection.stats,
|
||||
floor_price: collection.floorPrice,
|
||||
},
|
||||
}
|
||||
})
|
||||
: []
|
||||
return formattedData.slice(0, MAX_SEARCH_RESULTS)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { blocklistedCollections } from 'nft/utils'
|
||||
|
||||
import { TimePeriod, TrendingCollection } from '../../types'
|
||||
|
||||
const NFT_API_URL = process.env.REACT_APP_TEMP_API_URL
|
||||
@@ -18,5 +20,5 @@ export const fetchTrendingCollections = async (payload: {
|
||||
|
||||
const data = await r.json()
|
||||
|
||||
return data ?? []
|
||||
return data.filter((collection: { address: string }) => !blocklistedCollections.includes(collection.address)) ?? []
|
||||
}
|
||||
|
||||
@@ -22,3 +22,8 @@ export const isInSameSudoSwapPool = (assetA: GenieAsset, assetB: GenieAsset): bo
|
||||
export const isInSameMarketplaceCollection = (assetA: GenieAsset, assetB: GenieAsset): boolean => {
|
||||
return assetA.address === assetB.address && assetA.marketplace === assetB.marketplace
|
||||
}
|
||||
|
||||
export const blocklistedCollections = [
|
||||
'0xd5eeac01b0d1d929d6cffaaf78020af137277293',
|
||||
'0x85c08fffa9510f87019efdcf986301873cbb10d6',
|
||||
]
|
||||
|
||||
@@ -58,11 +58,13 @@ const Profile = lazy(() => import('nft/pages/profile/profile'))
|
||||
const Asset = lazy(() => import('nft/pages/asset/Asset'))
|
||||
|
||||
// Placeholder API key. Actual API key used in the proxy server
|
||||
const ANALYTICS_DUMMY_KEY = '00000000000000000000000000000000'
|
||||
const ANALYTICS_PROXY_URL = process.env.REACT_APP_AMPLITUDE_PROXY_URL
|
||||
const AMPLITUDE_DUMMY_KEY = '00000000000000000000000000000000'
|
||||
const AMPLITUDE_PROXY_URL = process.env.REACT_APP_AMPLITUDE_PROXY_URL
|
||||
const STATSIG_DUMMY_KEY = 'client-0000000000000000000000000000000000000000000'
|
||||
const STATSIG_PROXY_URL = process.env.REACT_APP_STATSIG_PROXY_URL
|
||||
const COMMIT_HASH = process.env.REACT_APP_GIT_COMMIT_HASH
|
||||
initializeAnalytics(ANALYTICS_DUMMY_KEY, OriginApplication.INTERFACE, {
|
||||
proxyUrl: ANALYTICS_PROXY_URL,
|
||||
initializeAnalytics(AMPLITUDE_DUMMY_KEY, OriginApplication.INTERFACE, {
|
||||
proxyUrl: AMPLITUDE_PROXY_URL,
|
||||
defaultEventName: SharedEventName.PAGE_VIEWED,
|
||||
commitHash: COMMIT_HASH,
|
||||
isProductionEnv: isProductionEnv(),
|
||||
@@ -210,10 +212,11 @@ export default function App() {
|
||||
<StatsigProvider
|
||||
user={statsigUser}
|
||||
// TODO: replace with proxy and cycle key
|
||||
sdkKey={process.env.REACT_APP_STATSIG_API_KEY ?? ''}
|
||||
sdkKey={STATSIG_DUMMY_KEY}
|
||||
waitForInitialization={false}
|
||||
options={{
|
||||
environment: { tier: getEnvName() },
|
||||
api: STATSIG_PROXY_URL,
|
||||
}}
|
||||
>
|
||||
<HeaderWrapper transparent={isHeaderTransparent}>
|
||||
|
||||
@@ -116,7 +116,7 @@ export default function MigrateV2() {
|
||||
<BodyWrapper style={{ padding: 24 }}>
|
||||
<AutoColumn gap="16px">
|
||||
<AutoRow style={{ alignItems: 'center', justifyContent: 'space-between' }} gap="8px">
|
||||
<BackArrow to="/pool/v2" />
|
||||
<BackArrow to="/pool" />
|
||||
<ThemedText.DeprecatedMediumHeader>
|
||||
<Trans>Migrate V2 Liquidity</Trans>
|
||||
</ThemedText.DeprecatedMediumHeader>
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { DEFAULT_LIST_OF_LISTS } from './../constants/lists'
|
||||
|
||||
const DEFAULT_LIST_PRIORITIES = DEFAULT_LIST_OF_LISTS.reduce<{ [listUrl: string]: number }>((memo, listUrl, index) => {
|
||||
memo[listUrl] = index + 1
|
||||
return memo
|
||||
}, {})
|
||||
const DEFAULT_LIST_PRIORITIES = DEFAULT_LIST_OF_LISTS.reduce(
|
||||
(acc, listUrl, index) => ({
|
||||
...acc,
|
||||
[listUrl]: index + 1,
|
||||
}),
|
||||
{}
|
||||
) as Record<string, number>
|
||||
|
||||
// use ordering of default list of lists to assign priority
|
||||
export default function sortByListPriority(urlA: string, urlB: string) {
|
||||
if (DEFAULT_LIST_PRIORITIES[urlA] && DEFAULT_LIST_PRIORITIES[urlB]) {
|
||||
return DEFAULT_LIST_PRIORITIES[urlA] - DEFAULT_LIST_PRIORITIES[urlB]
|
||||
}
|
||||
return 0
|
||||
const A = DEFAULT_LIST_PRIORITIES[urlA]
|
||||
const B = DEFAULT_LIST_PRIORITIES[urlB]
|
||||
if (!A) return 0
|
||||
if (!B) return 0
|
||||
return A - B
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import { CHAIN_NAME_TO_CHAIN_ID } from 'graphql/data/util'
|
||||
|
||||
export function getNativeTokenDBAddress(chain: Chain): string | undefined {
|
||||
const pageChainId = CHAIN_NAME_TO_CHAIN_ID[chain]
|
||||
if (pageChainId === undefined) {
|
||||
return undefined
|
||||
}
|
||||
switch (chain) {
|
||||
case Chain.Celo:
|
||||
case Chain.Polygon:
|
||||
|
||||
@@ -92,3 +92,9 @@ export function warningSeverity(priceImpact: Percent | undefined): WarningSeveri
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
export function getPriceImpactWarning(priceImpact: Percent): 'warning' | 'error' | undefined {
|
||||
if (priceImpact.greaterThan(ALLOWED_PRICE_IMPACT_HIGH)) return 'error'
|
||||
if (priceImpact.greaterThan(ALLOWED_PRICE_IMPACT_MEDIUM)) return 'warning'
|
||||
return
|
||||
}
|
||||
|
||||
Binary file not shown.
408
yarn.lock
408
yarn.lock
@@ -1156,12 +1156,12 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@>=7.17.0", "@babel/runtime@^7.0.0", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
||||
version "7.19.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.4.tgz#a42f814502ee467d55b38dd1c256f53a7b885c78"
|
||||
integrity sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==
|
||||
"@babel/runtime@>=7.17.0", "@babel/runtime@^7.0.0", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
||||
version "7.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673"
|
||||
integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
regenerator-runtime "^0.13.11"
|
||||
|
||||
"@babel/template@^7.10.4", "@babel/template@^7.12.13", "@babel/template@^7.15.4", "@babel/template@^7.16.7", "@babel/template@^7.18.10", "@babel/template@^7.3.3":
|
||||
version "7.18.10"
|
||||
@@ -1210,25 +1210,26 @@
|
||||
exec-sh "^0.3.2"
|
||||
minimist "^1.2.0"
|
||||
|
||||
"@coinbase/wallet-sdk@^3.3.0":
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@coinbase/wallet-sdk/-/wallet-sdk-3.3.0.tgz#e77383bce1388e5367dc35f8309702e73be47503"
|
||||
integrity sha512-Prmxs5eYRxe5i+kDSsny97oPG4Pa5PhLmNDx8f7UQrvlPowGy5Tg0gHOqCie6ck2shVMdW8sKJ+RCLIRZ9kIjA==
|
||||
"@coinbase/wallet-sdk@^3.6.4":
|
||||
version "3.6.4"
|
||||
resolved "https://registry.yarnpkg.com/@coinbase/wallet-sdk/-/wallet-sdk-3.6.4.tgz#00b4325c501ec5cdd07ac1b365ab226cb3df3a22"
|
||||
integrity sha512-2ecCT0/pmaMNVyMF7J1ZLFTfLnpnrHNQOGyIcbMBIepeqlE3jndjU023OdwwVLrLXyvfyelJ8K1iwAOvyEZxUw==
|
||||
dependencies:
|
||||
"@metamask/safe-event-emitter" "2.0.0"
|
||||
"@solana/web3.js" "^1.70.1"
|
||||
bind-decorator "^1.0.11"
|
||||
bn.js "^5.1.1"
|
||||
buffer "^6.0.3"
|
||||
clsx "^1.1.0"
|
||||
eth-block-tracker "4.4.3"
|
||||
eth-json-rpc-filters "4.2.2"
|
||||
eth-json-rpc-filters "5.1.0"
|
||||
eth-rpc-errors "4.0.2"
|
||||
js-sha256 "0.9.0"
|
||||
json-rpc-engine "6.1.0"
|
||||
keccak "^3.0.1"
|
||||
preact "^10.5.9"
|
||||
qs "^6.10.3"
|
||||
rxjs "^6.6.3"
|
||||
sha.js "^2.4.11"
|
||||
stream-browserify "^3.0.0"
|
||||
util "^0.12.4"
|
||||
|
||||
@@ -3251,6 +3252,21 @@
|
||||
resolved "https://registry.npmjs.org/@multiformats/base-x/-/base-x-4.0.1.tgz"
|
||||
integrity sha512-eMk0b9ReBbV23xXU693TAIrLyeO5iTgBZGSJfpqriG8UkYvr/hC9u9pyMlAakDNHWmbhMZCDs6KQO0jzKD8OTw==
|
||||
|
||||
"@noble/ed25519@^1.7.0":
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123"
|
||||
integrity sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==
|
||||
|
||||
"@noble/hashes@^1.1.2":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12"
|
||||
integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==
|
||||
|
||||
"@noble/secp256k1@^1.6.3":
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c"
|
||||
integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||
@@ -3680,6 +3696,35 @@
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
|
||||
"@solana/buffer-layout@^4.0.0":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15"
|
||||
integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==
|
||||
dependencies:
|
||||
buffer "~6.0.3"
|
||||
|
||||
"@solana/web3.js@^1.70.1":
|
||||
version "1.73.3"
|
||||
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.73.3.tgz#60e6bd68f6f364d4be360b1e0a03a0a68468a029"
|
||||
integrity sha512-vHRMo589XEIpoujpE2sZZ1aMZvfA1ImKfNxobzEFyMb+H5j6mRRUXfdgWD0qJ0sm11e5BcBC7HPeRXJB+7f3Lg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
"@noble/ed25519" "^1.7.0"
|
||||
"@noble/hashes" "^1.1.2"
|
||||
"@noble/secp256k1" "^1.6.3"
|
||||
"@solana/buffer-layout" "^4.0.0"
|
||||
agentkeepalive "^4.2.1"
|
||||
bigint-buffer "^1.1.5"
|
||||
bn.js "^5.0.0"
|
||||
borsh "^0.7.0"
|
||||
bs58 "^4.0.1"
|
||||
buffer "6.0.1"
|
||||
fast-stable-stringify "^1.0.0"
|
||||
jayson "^3.4.4"
|
||||
node-fetch "^2.6.7"
|
||||
rpc-websockets "^7.5.1"
|
||||
superstruct "^0.14.2"
|
||||
|
||||
"@styled-system/background@^5.1.2":
|
||||
version "5.1.2"
|
||||
resolved "https://registry.npmjs.org/@styled-system/background/-/background-5.1.2.tgz"
|
||||
@@ -4025,13 +4070,6 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.3.0"
|
||||
|
||||
"@types/bn.js@^4.11.3":
|
||||
version "4.11.6"
|
||||
resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz"
|
||||
integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/bn.js@^5.1.0":
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68"
|
||||
@@ -4039,6 +4077,13 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/connect@^3.4.33":
|
||||
version "3.4.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
|
||||
integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/d3-array@^2":
|
||||
version "2.12.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-2.12.3.tgz#8d16d51fb04ad5a5a8ebe14eb8263a579f1efdd1"
|
||||
@@ -4444,6 +4489,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b"
|
||||
integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==
|
||||
|
||||
"@types/node@^12.12.54":
|
||||
version "12.20.55"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240"
|
||||
integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==
|
||||
|
||||
"@types/node@^13.13.5":
|
||||
version "13.13.52"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz"
|
||||
@@ -4708,6 +4758,13 @@
|
||||
anymatch "^3.0.0"
|
||||
source-map "^0.6.0"
|
||||
|
||||
"@types/ws@^7.4.4":
|
||||
version "7.4.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702"
|
||||
integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/ws@^8.0.0":
|
||||
version "8.5.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d"
|
||||
@@ -4931,15 +4988,15 @@
|
||||
"@typescript-eslint/types" "5.47.0"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@uniswap/analytics-events@^2.3.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/analytics-events/-/analytics-events-2.3.0.tgz#e4d6b29633c09872be3b9b760b1a192b96368887"
|
||||
integrity sha512-oShunkYEfa45RQAtl2aQfF91gfX4QirLa/fR+FyL5jfl+Ei4AZ1ihtyVjJ1VLOJlObX1p08JjlpA0yxqDwPYHw==
|
||||
"@uniswap/analytics-events@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/analytics-events/-/analytics-events-2.4.0.tgz#910f727bf4c72f5d1890f17daec4687dc44ee6c0"
|
||||
integrity sha512-oZl2KRCSTAO8C3sxEFX6BEdGujdPs8tk/Zyx7UwOZOUDcim3mxx6rsdRvnwsAgkZAJjV9I1HSUR7JEeJmQkRmQ==
|
||||
|
||||
"@uniswap/analytics@^1.3.0":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/analytics/-/analytics-1.3.0.tgz#42de08949a7d529ebba647d76801f143792c132a"
|
||||
integrity sha512-cwx3HDxcqehr5uUnnAJ20lak9jA68e+l8ww/s4XxoJzedkdHz0TWXc4+ZZ2iukKEun4oU/d3clrU6u3Cu6xDpg==
|
||||
"@uniswap/analytics@^1.3.1":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/analytics/-/analytics-1.3.1.tgz#086a681fc483c08e1b3d896cce287bc162ad0c1d"
|
||||
integrity sha512-wB8J+e9oeu+VSx3tgfA304g7MKf6zuAesFeEGKdD1pI2LNOoMQHczbnf8I8lPjPYnXxLvdbGVKRQZXWaI+jTGw==
|
||||
dependencies:
|
||||
"@amplitude/analytics-browser" "^1.5.8"
|
||||
react "^18.2.0"
|
||||
@@ -5194,10 +5251,10 @@
|
||||
"@uniswap/v3-core" "1.0.0"
|
||||
"@uniswap/v3-periphery" "^1.0.1"
|
||||
|
||||
"@uniswap/widgets@^2.29.3":
|
||||
version "2.29.3"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/widgets/-/widgets-2.29.3.tgz#1b2f0d4f7f4db16d6d12f40204bcee6a67e46c1c"
|
||||
integrity sha512-gsyiNxeqcj5Wn5IsaAKIz9M1v9lkmYKGxCrJHWADw8UyuTrPnL7qXg6GkBRR5kYkd+eeK6lK28qc1BEzl7dvmQ==
|
||||
"@uniswap/widgets@^2.40.0":
|
||||
version "2.40.0"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/widgets/-/widgets-2.40.0.tgz#98539f31cc21a8e70ced86da65db642f3380db14"
|
||||
integrity sha512-55I6r8a3XfWAEFfU6eAj4BUbaYRBPyrbfzaedAy0+9SAntnxxT7wyh3DMC9MoMLEwd4PPLemWyLfVQTVIoYn0g==
|
||||
dependencies:
|
||||
"@babel/runtime" ">=7.17.0"
|
||||
"@fontsource/ibm-plex-mono" "^4.5.1"
|
||||
@@ -6047,6 +6104,14 @@
|
||||
resolved "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz"
|
||||
integrity sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==
|
||||
|
||||
JSONStream@^1.3.5:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
|
||||
integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
|
||||
dependencies:
|
||||
jsonparse "^1.2.0"
|
||||
through ">=2.2.7 <3"
|
||||
|
||||
abab@^2.0.3, abab@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
|
||||
@@ -6135,6 +6200,15 @@ agent-base@6:
|
||||
dependencies:
|
||||
debug "4"
|
||||
|
||||
agentkeepalive@^4.2.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717"
|
||||
integrity sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==
|
||||
dependencies:
|
||||
debug "^4.1.0"
|
||||
depd "^1.1.2"
|
||||
humanize-ms "^1.2.1"
|
||||
|
||||
aggregate-error@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
|
||||
@@ -6940,6 +7014,13 @@ big.js@^5.2.2:
|
||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
|
||||
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
|
||||
|
||||
bigint-buffer@^1.1.5:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442"
|
||||
integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==
|
||||
dependencies:
|
||||
bindings "^1.3.0"
|
||||
|
||||
bignumber.js@^8.1.1:
|
||||
version "8.1.1"
|
||||
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-8.1.1.tgz#4b072ae5aea9c20f6730e4e5d529df1271c4d885"
|
||||
@@ -6965,9 +7046,9 @@ bind-decorator@^1.0.11:
|
||||
resolved "https://registry.npmjs.org/bind-decorator/-/bind-decorator-1.0.11.tgz"
|
||||
integrity sha1-5BvAah9l3ZzsR2yRxdrzl4SIJS8=
|
||||
|
||||
bindings@^1.5.0:
|
||||
bindings@^1.3.0, bindings@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz"
|
||||
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
|
||||
integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
|
||||
dependencies:
|
||||
file-uri-to-path "1.0.0"
|
||||
@@ -7011,7 +7092,7 @@ bn.js@4.11.8:
|
||||
resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz"
|
||||
integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
|
||||
|
||||
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9:
|
||||
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9:
|
||||
version "4.12.0"
|
||||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
|
||||
integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
|
||||
@@ -7054,6 +7135,15 @@ boolbase@^1.0.0, boolbase@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
|
||||
|
||||
borsh@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a"
|
||||
integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==
|
||||
dependencies:
|
||||
bn.js "^5.2.0"
|
||||
bs58 "^4.0.0"
|
||||
text-encoding-utf-8 "^1.0.2"
|
||||
|
||||
boxen@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz"
|
||||
@@ -7203,10 +7293,10 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.19.1, browserslist@^4
|
||||
node-releases "^2.0.6"
|
||||
update-browserslist-db "^1.0.9"
|
||||
|
||||
bs58@^4.0.0:
|
||||
bs58@^4.0.0, bs58@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz"
|
||||
integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo=
|
||||
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
|
||||
integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==
|
||||
dependencies:
|
||||
base-x "^3.0.2"
|
||||
|
||||
@@ -7226,11 +7316,6 @@ bser@2.1.1:
|
||||
dependencies:
|
||||
node-int64 "^0.4.0"
|
||||
|
||||
btoa@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz"
|
||||
integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==
|
||||
|
||||
buffer-alloc-unsafe@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz"
|
||||
@@ -7284,6 +7369,14 @@ buffer-xor@^1.0.3:
|
||||
resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
|
||||
integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=
|
||||
|
||||
buffer@6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.1.tgz#3cbea8c1463e5a0779e30b66d4c88c6ffa182ac2"
|
||||
integrity sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ==
|
||||
dependencies:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.2.1"
|
||||
|
||||
buffer@^4.3.0:
|
||||
version "4.9.2"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
|
||||
@@ -7301,7 +7394,7 @@ buffer@^5.2.0, buffer@^5.4.3, buffer@^5.5.0, buffer@^5.6.0:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.1.13"
|
||||
|
||||
buffer@^6.0.3:
|
||||
buffer@^6.0.3, buffer@~6.0.3:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
|
||||
integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
|
||||
@@ -7309,10 +7402,10 @@ buffer@^6.0.3:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.2.1"
|
||||
|
||||
bufferutil@^4.0.6:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.6.tgz#ebd6c67c7922a0e902f053e5d8be5ec850e48433"
|
||||
integrity sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==
|
||||
bufferutil@^4.0.1, bufferutil@^4.0.6:
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.7.tgz#60c0d19ba2c992dd8273d3f73772ffc894c153ad"
|
||||
integrity sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==
|
||||
dependencies:
|
||||
node-gyp-build "^4.3.0"
|
||||
|
||||
@@ -7842,7 +7935,7 @@ cliui@^8.0.1:
|
||||
strip-ansi "^6.0.1"
|
||||
wrap-ansi "^7.0.0"
|
||||
|
||||
clone@2.x, clone@^2.1.1:
|
||||
clone@2.x:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
|
||||
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
|
||||
@@ -7986,7 +8079,7 @@ commander@7:
|
||||
resolved "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz"
|
||||
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
|
||||
|
||||
commander@^2.20.0:
|
||||
commander@^2.20.0, commander@^2.20.3:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
@@ -9184,15 +9277,20 @@ delaunator@5:
|
||||
dependencies:
|
||||
robust-predicates "^3.0.0"
|
||||
|
||||
delay@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d"
|
||||
integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
||||
|
||||
depd@~1.1.2:
|
||||
depd@^1.1.2, depd@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
|
||||
integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
|
||||
|
||||
dependency-graph@^0.11.0:
|
||||
version "0.11.0"
|
||||
@@ -9690,6 +9788,18 @@ es6-iterator@2.0.3, es6-iterator@~2.0.3:
|
||||
es5-ext "^0.10.35"
|
||||
es6-symbol "^3.1.1"
|
||||
|
||||
es6-promise@^4.0.3:
|
||||
version "4.2.8"
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
|
||||
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
|
||||
|
||||
es6-promisify@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
|
||||
integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==
|
||||
dependencies:
|
||||
es6-promise "^4.0.3"
|
||||
|
||||
es6-symbol@^3.1.1, es6-symbol@~3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
|
||||
@@ -10080,35 +10190,17 @@ eth-block-tracker@4.4.3:
|
||||
pify "^3.0.0"
|
||||
safe-event-emitter "^1.0.1"
|
||||
|
||||
eth-json-rpc-filters@4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-4.2.2.tgz#eb35e1dfe9357ace8a8908e7daee80b2cd60a10d"
|
||||
integrity sha512-DGtqpLU7bBg63wPMWg1sCpkKCf57dJ+hj/k3zF26anXMzkmtSBDExL8IhUu7LUd34f0Zsce3PYNO2vV2GaTzaw==
|
||||
eth-json-rpc-filters@5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-5.1.0.tgz#f0c2aeaec2a45e2dc6ca1b9843d8e85447821427"
|
||||
integrity sha512-fos+9xmoa1A2Ytsc9eYof17r81BjdJOUcGcgZn4K/tKdCCTb+a8ytEtwlu1op5qsXFDlgGmstTELFrDEc89qEQ==
|
||||
dependencies:
|
||||
"@metamask/safe-event-emitter" "^2.0.0"
|
||||
async-mutex "^0.2.6"
|
||||
eth-json-rpc-middleware "^6.0.0"
|
||||
eth-query "^2.1.2"
|
||||
json-rpc-engine "^6.1.0"
|
||||
pify "^5.0.0"
|
||||
|
||||
eth-json-rpc-middleware@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-6.0.0.tgz"
|
||||
integrity sha512-qqBfLU2Uq1Ou15Wox1s+NX05S9OcAEL4JZ04VZox2NS0U+RtCMjSxzXhLFWekdShUPZ+P8ax3zCO2xcPrp6XJQ==
|
||||
dependencies:
|
||||
btoa "^1.2.1"
|
||||
clone "^2.1.1"
|
||||
eth-query "^2.1.2"
|
||||
eth-rpc-errors "^3.0.0"
|
||||
eth-sig-util "^1.4.2"
|
||||
ethereumjs-util "^5.1.2"
|
||||
json-rpc-engine "^5.3.0"
|
||||
json-stable-stringify "^1.0.1"
|
||||
node-fetch "^2.6.1"
|
||||
pify "^3.0.0"
|
||||
safe-event-emitter "^1.0.1"
|
||||
|
||||
eth-query@^2.1.0, eth-query@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmjs.org/eth-query/-/eth-query-2.1.2.tgz"
|
||||
@@ -10124,21 +10216,6 @@ eth-rpc-errors@4.0.2, eth-rpc-errors@^4.0.2:
|
||||
dependencies:
|
||||
fast-safe-stringify "^2.0.6"
|
||||
|
||||
eth-rpc-errors@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-3.0.0.tgz"
|
||||
integrity sha512-iPPNHPrLwUlR9xCSYm7HHQjWBasor3+KZfRvwEWxMz3ca0yqnlBeJrnyphkGIXZ4J7AMAaOLmwy4AWhnxOiLxg==
|
||||
dependencies:
|
||||
fast-safe-stringify "^2.0.6"
|
||||
|
||||
eth-sig-util@^1.4.2:
|
||||
version "1.4.2"
|
||||
resolved "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz"
|
||||
integrity sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=
|
||||
dependencies:
|
||||
ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git"
|
||||
ethereumjs-util "^5.1.1"
|
||||
|
||||
ethereum-bloom-filters@^1.0.6:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a"
|
||||
@@ -10167,39 +10244,6 @@ ethereum-cryptography@^0.1.3:
|
||||
secp256k1 "^4.0.1"
|
||||
setimmediate "^1.0.5"
|
||||
|
||||
"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git":
|
||||
version "0.6.8"
|
||||
resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#ee3994657fa7a427238e6ba92a84d0b529bbcde0"
|
||||
dependencies:
|
||||
bn.js "^4.11.8"
|
||||
ethereumjs-util "^6.0.0"
|
||||
|
||||
ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz"
|
||||
integrity sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==
|
||||
dependencies:
|
||||
bn.js "^4.11.0"
|
||||
create-hash "^1.1.2"
|
||||
elliptic "^6.5.2"
|
||||
ethereum-cryptography "^0.1.3"
|
||||
ethjs-util "^0.1.3"
|
||||
rlp "^2.0.0"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
ethereumjs-util@^6.0.0:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz"
|
||||
integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==
|
||||
dependencies:
|
||||
"@types/bn.js" "^4.11.3"
|
||||
bn.js "^4.11.0"
|
||||
create-hash "^1.1.2"
|
||||
elliptic "^6.5.2"
|
||||
ethereum-cryptography "^0.1.3"
|
||||
ethjs-util "0.1.6"
|
||||
rlp "^2.2.3"
|
||||
|
||||
ethereumjs-util@^7.1.0:
|
||||
version "7.1.5"
|
||||
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181"
|
||||
@@ -10255,14 +10299,6 @@ ethjs-unit@0.1.6:
|
||||
bn.js "4.11.6"
|
||||
number-to-bn "1.7.0"
|
||||
|
||||
ethjs-util@0.1.6, ethjs-util@^0.1.3:
|
||||
version "0.1.6"
|
||||
resolved "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz"
|
||||
integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==
|
||||
dependencies:
|
||||
is-hex-prefixed "1.0.0"
|
||||
strip-hex-prefix "1.0.0"
|
||||
|
||||
eval@0.1.6:
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.6.tgz#9620d7d8c85515e97e6b47c5814f46ae381cb3cc"
|
||||
@@ -10523,6 +10559,11 @@ extsprintf@1.3.0, extsprintf@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
|
||||
|
||||
eyes@^0.1.8:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0"
|
||||
integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==
|
||||
|
||||
fast-deep-equal@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz"
|
||||
@@ -10564,6 +10605,11 @@ fast-safe-stringify@^2.0.6:
|
||||
resolved "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz"
|
||||
integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==
|
||||
|
||||
fast-stable-stringify@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313"
|
||||
integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==
|
||||
|
||||
fast-url-parser@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz"
|
||||
@@ -11676,6 +11722,13 @@ human-signals@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
||||
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
|
||||
|
||||
humanize-ms@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
|
||||
integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==
|
||||
dependencies:
|
||||
ms "^2.0.0"
|
||||
|
||||
iconv-lite@0.4.24, iconv-lite@^0.4.24:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
|
||||
@@ -12483,6 +12536,11 @@ isomorphic-ws@5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf"
|
||||
integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==
|
||||
|
||||
isomorphic-ws@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc"
|
||||
integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==
|
||||
|
||||
isstream@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||
@@ -12539,6 +12597,25 @@ javascript-stringify@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79"
|
||||
integrity sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==
|
||||
|
||||
jayson@^3.4.4:
|
||||
version "3.7.0"
|
||||
resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.7.0.tgz#b735b12d06d348639ae8230d7a1e2916cb078f25"
|
||||
integrity sha512-tfy39KJMrrXJ+mFcMpxwBvFDetS8LAID93+rycFglIQM4kl3uNR3W4lBLE/FFhsoUCEox5Dt2adVpDm/XtebbQ==
|
||||
dependencies:
|
||||
"@types/connect" "^3.4.33"
|
||||
"@types/node" "^12.12.54"
|
||||
"@types/ws" "^7.4.4"
|
||||
JSONStream "^1.3.5"
|
||||
commander "^2.20.3"
|
||||
delay "^5.0.0"
|
||||
es6-promisify "^5.0.0"
|
||||
eyes "^0.1.8"
|
||||
isomorphic-ws "^4.0.1"
|
||||
json-stringify-safe "^5.0.1"
|
||||
lodash "^4.17.20"
|
||||
uuid "^8.3.2"
|
||||
ws "^7.4.5"
|
||||
|
||||
jest-changed-files@^26.6.2:
|
||||
version "26.6.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0"
|
||||
@@ -13019,7 +13096,7 @@ js-base64@^3.7.2:
|
||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.2.tgz#816d11d81a8aff241603d19ce5761e13e41d7745"
|
||||
integrity sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==
|
||||
|
||||
js-sha256@0.9.0, js-sha256@^0.9.0:
|
||||
js-sha256@^0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966"
|
||||
integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==
|
||||
@@ -13120,14 +13197,6 @@ json-rpc-engine@6.1.0, json-rpc-engine@^6.1.0:
|
||||
"@metamask/safe-event-emitter" "^2.0.0"
|
||||
eth-rpc-errors "^4.0.2"
|
||||
|
||||
json-rpc-engine@^5.3.0:
|
||||
version "5.4.0"
|
||||
resolved "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-5.4.0.tgz"
|
||||
integrity sha512-rAffKbPoNDjuRnXkecTjnsE3xLLrb00rEkdgalINhaYVYIxDwWtvYBr9UFbhTvPB1B2qUOLoFd/cV6f4Q7mh7g==
|
||||
dependencies:
|
||||
eth-rpc-errors "^3.0.0"
|
||||
safe-event-emitter "^1.0.1"
|
||||
|
||||
json-rpc-random-id@^1.0.0, json-rpc-random-id@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz"
|
||||
@@ -13160,10 +13229,10 @@ json-stable-stringify@^1.0.1:
|
||||
dependencies:
|
||||
jsonify "~0.0.0"
|
||||
|
||||
json-stringify-safe@~5.0.1:
|
||||
json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
||||
integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==
|
||||
|
||||
json-to-pretty-yaml@^1.2.2:
|
||||
version "1.2.2"
|
||||
@@ -13211,6 +13280,11 @@ jsonify@~0.0.0:
|
||||
resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz"
|
||||
integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=
|
||||
|
||||
jsonparse@^1.2.0:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
|
||||
integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==
|
||||
|
||||
jsonwebtoken@^8.5.1:
|
||||
version "8.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d"
|
||||
@@ -16733,10 +16807,10 @@ regenerator-runtime@^0.11.0:
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
||||
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
|
||||
|
||||
regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
|
||||
version "0.13.9"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
|
||||
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
|
||||
regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
|
||||
version "0.13.11"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
|
||||
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
|
||||
|
||||
regenerator-transform@^0.14.2:
|
||||
version "0.14.5"
|
||||
@@ -17106,7 +17180,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
|
||||
hash-base "^3.0.0"
|
||||
inherits "^2.0.1"
|
||||
|
||||
rlp@^2.0.0, rlp@^2.2.3, rlp@^2.2.4:
|
||||
rlp@^2.2.4:
|
||||
version "2.2.7"
|
||||
resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf"
|
||||
integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==
|
||||
@@ -17153,6 +17227,19 @@ rollup@^1.31.1:
|
||||
"@types/node" "*"
|
||||
acorn "^7.1.0"
|
||||
|
||||
rpc-websockets@^7.5.1:
|
||||
version "7.5.1"
|
||||
resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.5.1.tgz#e0a05d525a97e7efc31a0617f093a13a2e10c401"
|
||||
integrity sha512-kGFkeTsmd37pHPMaHIgN1LVKXMi0JD782v4Ds9ZKtLlwdTKjn+CxM9A9/gLT2LaOuEcEFGL98h1QWQtlOIdW0w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.17.2"
|
||||
eventemitter3 "^4.0.7"
|
||||
uuid "^8.3.2"
|
||||
ws "^8.5.0"
|
||||
optionalDependencies:
|
||||
bufferutil "^4.0.1"
|
||||
utf-8-validate "^5.0.2"
|
||||
|
||||
rsvp@^4.8.4:
|
||||
version "4.8.5"
|
||||
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
|
||||
@@ -17518,7 +17605,7 @@ setprototypeof@1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
|
||||
integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
|
||||
|
||||
sha.js@^2.4.0, sha.js@^2.4.8:
|
||||
sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8:
|
||||
version "2.4.11"
|
||||
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
|
||||
integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
|
||||
@@ -18213,6 +18300,11 @@ stylehacks@^4.0.0:
|
||||
postcss "^7.0.0"
|
||||
postcss-selector-parser "^3.0.0"
|
||||
|
||||
superstruct@^0.14.2:
|
||||
version "0.14.2"
|
||||
resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b"
|
||||
integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==
|
||||
|
||||
supports-color@^5.3.0, supports-color@^5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
@@ -18431,6 +18523,11 @@ test-value@^2.1.0:
|
||||
array-back "^1.0.3"
|
||||
typical "^2.6.0"
|
||||
|
||||
text-encoding-utf-8@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13"
|
||||
integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==
|
||||
|
||||
text-table@0.2.0, text-table@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
|
||||
@@ -18459,10 +18556,10 @@ through2@^2.0.0:
|
||||
readable-stream "~2.3.6"
|
||||
xtend "~4.0.1"
|
||||
|
||||
through@^2.3.6, through@^2.3.8:
|
||||
"through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
|
||||
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
|
||||
|
||||
thunky@^1.0.2:
|
||||
version "1.1.0"
|
||||
@@ -19164,10 +19261,10 @@ use@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
|
||||
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
|
||||
|
||||
utf-8-validate@^5.0.8:
|
||||
version "5.0.9"
|
||||
resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.9.tgz#ba16a822fbeedff1a58918f2a6a6b36387493ea3"
|
||||
integrity sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==
|
||||
utf-8-validate@^5.0.2, utf-8-validate@^5.0.8:
|
||||
version "5.0.10"
|
||||
resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2"
|
||||
integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==
|
||||
dependencies:
|
||||
node-gyp-build "^4.3.0"
|
||||
|
||||
@@ -19929,11 +20026,16 @@ ws@7.5.3:
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74"
|
||||
integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==
|
||||
|
||||
ws@8.11.0, ws@>=7.4.6:
|
||||
ws@8.11.0:
|
||||
version "8.11.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143"
|
||||
integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
|
||||
|
||||
ws@>=7.4.6, ws@^8.5.0:
|
||||
version "8.12.1"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.1.tgz#c51e583d79140b5e42e39be48c934131942d4a8f"
|
||||
integrity sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==
|
||||
|
||||
ws@^6.2.1:
|
||||
version "6.2.2"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e"
|
||||
|
||||
Reference in New Issue
Block a user