diff --git a/.gitignore b/.gitignore index c349c858..2d99d835 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ yarn-error.log* # typescript tsconfig.tsbuildinfo + +# Sentry Auth Token +.sentryclirc diff --git a/components/account/CreateAccountForm.tsx b/components/account/CreateAccountForm.tsx index aec6938b..d22574fc 100644 --- a/components/account/CreateAccountForm.tsx +++ b/components/account/CreateAccountForm.tsx @@ -54,10 +54,7 @@ const CreateAccountForm = ({ group, newAccountNum, name || `Account ${newAccountNum + 1}`, - undefined, // tokenCount - undefined, // serum3Count - 8, // perpCount - 10 // perpOoCount + 16 // tokenCount ) if (tx) { const pk = wallet.adapter.publicKey diff --git a/components/account/FundingChart.tsx b/components/account/FundingChart.tsx index 1863fc64..4145a1bd 100644 --- a/components/account/FundingChart.tsx +++ b/components/account/FundingChart.tsx @@ -8,7 +8,7 @@ import { HourlyFundingData, HourlyFundingStatsData, } from 'types' -import { MANGO_DATA_API_URL } from 'utils/constants' +import { DAILY_MILLISECONDS, MANGO_DATA_API_URL } from 'utils/constants' import { formatCurrencyValue } from 'utils/numbers' import { TooltipProps } from 'recharts/types/component/Tooltip' import { @@ -191,7 +191,7 @@ const FundingChart = ({ hideChart }: { hideChart: () => void }) => { const filteredData: HourlyFundingChartData[] = useMemo(() => { if (!chartData.length) return [] - const start = Number(daysToShow) * 86400000 + const start = Number(daysToShow) * DAILY_MILLISECONDS const filtered = chartData.filter((d: HourlyFundingChartData) => { const date = new Date() if (daysToShow === '30') { diff --git a/components/account/VolumeChart.tsx b/components/account/VolumeChart.tsx index 6be22bc4..e13d6bc9 100644 --- a/components/account/VolumeChart.tsx +++ b/components/account/VolumeChart.tsx @@ -24,6 +24,7 @@ import { ArrowLeftIcon, NoSymbolIcon } from '@heroicons/react/20/solid' import { FadeInFadeOut } from '@components/shared/Transitions' import ContentBox from '@components/shared/ContentBox' import SheenLoader from '@components/shared/SheenLoader' +import { DAILY_MILLISECONDS } from 'utils/constants' const VolumeChart = ({ chartData, @@ -123,7 +124,7 @@ const VolumeChart = ({ const filteredData: FormattedHourlyAccountVolumeData[] = useMemo(() => { if (!chartData || !chartData.length) return [] - const start = Number(daysToShow) * 86400000 + const start = Number(daysToShow) * DAILY_MILLISECONDS const filtered = chartData.filter((d: FormattedHourlyAccountVolumeData) => { const date = new Date() if (daysToShow === '30') { diff --git a/components/governance/Vote/VoteCountdown.tsx b/components/governance/Vote/VoteCountdown.tsx index 6023b300..987ef8b1 100644 --- a/components/governance/Vote/VoteCountdown.tsx +++ b/components/governance/Vote/VoteCountdown.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react' import { Governance, Proposal } from '@solana/spl-governance' import dayjs from 'dayjs' import { useTranslation } from 'next-i18next' +import { DAILY_SECONDS } from 'utils/constants' interface CountdownState { days: number @@ -53,8 +54,8 @@ export function VoteCountdown({ return ZeroCountdown } - const days = Math.floor(timeToVoteEnd / 86400) - timeToVoteEnd -= days * 86400 + const days = Math.floor(timeToVoteEnd / DAILY_SECONDS) + timeToVoteEnd -= days * DAILY_SECONDS const hours = Math.floor(timeToVoteEnd / 3600) % 24 timeToVoteEnd -= hours * 3600 diff --git a/components/modals/PnlHistoryModal.tsx b/components/modals/PnlHistoryModal.tsx index 81cf8a69..c5abf171 100644 --- a/components/modals/PnlHistoryModal.tsx +++ b/components/modals/PnlHistoryModal.tsx @@ -8,6 +8,7 @@ import SheenLoader from '@components/shared/SheenLoader' import { NoSymbolIcon } from '@heroicons/react/20/solid' import { PerformanceDataItem } from 'types' import useAccountPerformanceData from 'hooks/useAccountPerformanceData' +import { DAILY_MILLISECONDS } from 'utils/constants' interface PnlChange { time: string @@ -33,7 +34,7 @@ const PnlHistoryModal = ({ if (!performanceData || !performanceData.length) return [] const dailyPnl = performanceData.filter((d: PerformanceDataItem) => { - const startTime = new Date().getTime() - 30 * 86400000 + const startTime = new Date().getTime() - 30 * DAILY_MILLISECONDS const dataDate = new Date(d.time) const dataTime = dataDate.getTime() return dataTime >= startTime && dataDate.getHours() === 0 diff --git a/components/modals/UserSetupModal.tsx b/components/modals/UserSetupModal.tsx index 92ea4601..85ba8bbb 100644 --- a/components/modals/UserSetupModal.tsx +++ b/components/modals/UserSetupModal.tsx @@ -88,10 +88,7 @@ const UserSetupModal = ({ group, 0, accountName || 'Account 1', - undefined, // tokenCount - undefined, // serum3Count - 8, // perpCount - 10 // perpOoCount + 16 // tokenCount ) actions.fetchMangoAccounts(publicKey) if (tx) { diff --git a/components/settings/RpcSettings.tsx b/components/settings/RpcSettings.tsx index cbb1c2cd..78fcfb01 100644 --- a/components/settings/RpcSettings.tsx +++ b/components/settings/RpcSettings.tsx @@ -23,8 +23,8 @@ const RPC_URLS = [ }, { label: 'Triton Dedicated', - value: process.env.TRITON_TOKEN - ? `https://mango.rpcpool.com/${process.env.TRITON_TOKEN}` + value: process.env.NEXT_PUBLIC_TRITON_TOKEN + ? `https://mango.rpcpool.com/${process.env.NEXT_PUBLIC_TRITON_TOKEN}` : 'https://mango.rpcpool.com/946ef7337da3f5b8d3e4a34e7f88', }, // { diff --git a/components/shared/DetailedAreaOrBarChart.tsx b/components/shared/DetailedAreaOrBarChart.tsx index 2e271f1a..4f3a0a51 100644 --- a/components/shared/DetailedAreaOrBarChart.tsx +++ b/components/shared/DetailedAreaOrBarChart.tsx @@ -25,7 +25,7 @@ import { FadeInFadeOut } from './Transitions' import ChartRangeButtons from './ChartRangeButtons' import Change from './Change' import useLocalStorageState from 'hooks/useLocalStorageState' -import { ANIMATION_SETTINGS_KEY } from 'utils/constants' +import { ANIMATION_SETTINGS_KEY, DAILY_MILLISECONDS } from 'utils/constants' import { formatNumericValue } from 'utils/numbers' import { INITIAL_ANIMATION_SETTINGS } from '@components/settings/AnimationSettings' import { AxisDomain } from 'recharts/types/util/types' @@ -120,7 +120,7 @@ const DetailedAreaOrBarChart: FunctionComponent< const filteredData = useMemo(() => { if (!data.length) return [] - const start = Number(daysToShow) * 86400000 + const start = Number(daysToShow) * DAILY_MILLISECONDS const filtered = data.filter((d: any) => { const dataTime = new Date(d[xKey]).getTime() const now = new Date().getTime() diff --git a/components/shared/MarketChange.tsx b/components/shared/MarketChange.tsx new file mode 100644 index 00000000..37e58a8b --- /dev/null +++ b/components/shared/MarketChange.tsx @@ -0,0 +1,67 @@ +import { MinusSmallIcon } from '@heroicons/react/20/solid' +import { DownTriangle, UpTriangle } from './DirectionTriangles' +import FormatNumericValue from './FormatNumericValue' +import { PerpMarket, Serum3Market } from '@blockworks-foundation/mango-v4' +import use24HourChange from 'hooks/use24HourChange' +import { useMemo } from 'react' +import SheenLoader from './SheenLoader' + +const MarketChange = ({ + market, + size, +}: { + market: PerpMarket | Serum3Market | undefined + size?: 'small' +}) => { + const { loading, spotChange, perpChange } = use24HourChange(market) + + const change = useMemo(() => { + if (!market) return + return market instanceof PerpMarket ? perpChange : spotChange + }, [perpChange, spotChange]) + + return loading ? ( + +
+ + ) : change && !isNaN(change) ? ( +
+ {change > 0 ? ( +
+ +
+ ) : change < 0 ? ( +
+ +
+ ) : ( + + )} +

0 + ? 'text-th-up' + : change < 0 + ? 'text-th-down' + : 'text-th-fgd-4' + }`} + > + + % +

+
+ ) : ( +

+ ) +} + +export default MarketChange diff --git a/components/stats/PerpMarketsOverviewTable.tsx b/components/stats/PerpMarketsOverviewTable.tsx index e36b26ea..42e3f81e 100644 --- a/components/stats/PerpMarketsOverviewTable.tsx +++ b/components/stats/PerpMarketsOverviewTable.tsx @@ -24,6 +24,7 @@ import SimpleAreaChart from '@components/shared/SimpleAreaChart' import { Disclosure, Transition } from '@headlessui/react' import { LinkButton } from '@components/shared/Button' import SoonBadge from '@components/shared/SoonBadge' +import { DAILY_SECONDS } from 'utils/constants' export const getOneDayPerpStats = ( stats: PerpStatsItem[] | null, @@ -33,7 +34,7 @@ export const getOneDayPerpStats = ( ? stats .filter((s) => s.perp_market === marketName) .filter((f) => { - const seconds = 86400 + const seconds = DAILY_SECONDS const dataTime = new Date(f.date_hour).getTime() / 1000 const now = new Date().getTime() / 1000 const limit = now - seconds diff --git a/components/stats/SpotMarketsTable.tsx b/components/stats/SpotMarketsTable.tsx index 83c3bc53..49e84f0a 100644 --- a/components/stats/SpotMarketsTable.tsx +++ b/components/stats/SpotMarketsTable.tsx @@ -20,6 +20,7 @@ import { fetchSpotVolume } from '@components/trade/AdvancedMarketHeader' import { TickerData } from 'types' import { Disclosure, Transition } from '@headlessui/react' import { ChevronDownIcon } from '@heroicons/react/20/solid' +import MarketChange from '@components/shared/MarketChange' const SpotMarketsTable = () => { const { t } = useTranslation('common') @@ -87,7 +88,7 @@ const SpotMarketsTable = () => { (m) => m.mint === mkt.serumMarketExternal.toString() ) - const change = + const birdeyeChange = birdeyeData && price ? ((price - birdeyeData.data[0].value) / birdeyeData.data[0].value) * @@ -131,7 +132,7 @@ const SpotMarketsTable = () => {
= 0 + birdeyeChange >= 0 ? COLORS.UP[theme] : COLORS.DOWN[theme] } @@ -153,7 +154,7 @@ const SpotMarketsTable = () => {
- +
diff --git a/components/swap/SwapReviewRouteInfo.tsx b/components/swap/SwapReviewRouteInfo.tsx index bff25335..898005d5 100644 --- a/components/swap/SwapReviewRouteInfo.tsx +++ b/components/swap/SwapReviewRouteInfo.tsx @@ -16,6 +16,7 @@ import { AddressLookupTableAccount, } from '@solana/web3.js' import Decimal from 'decimal.js' +import * as sentry from '@sentry/nextjs' import mangoStore from '@store/mangoStore' import Button, { IconButton } from '../shared/Button' @@ -313,6 +314,7 @@ const SwapReviewRouteInfo = ({ await actions.reloadMangoAccount() } catch (e) { console.error('onSwap error: ', e) + sentry.captureException(e) if (isMangoError(e)) { notify({ title: 'Transaction failed', diff --git a/components/swap/SwapTokenChart.tsx b/components/swap/SwapTokenChart.tsx index 7611ae95..d6f76d0c 100644 --- a/components/swap/SwapTokenChart.tsx +++ b/components/swap/SwapTokenChart.tsx @@ -166,8 +166,12 @@ const SwapTokenChart = () => { const loadSwapHistory = mangoStore((s) => s.mangoAccount.swapHistory.loading) const [showSwaps, setShowSwaps] = useState(true) - const coingeckoDataQuery = useQuery( - ['chart-data', baseTokenId, quoteTokenId, daysToShow], + const { + data: coingeckoDataQuery, + isLoading, + isFetching, + } = useQuery( + ['swap-chart-data', baseTokenId, quoteTokenId, daysToShow], () => fetchChartData(baseTokenId, quoteTokenId, daysToShow), { cacheTime: 1000 * 60 * 15, @@ -178,11 +182,11 @@ const SwapTokenChart = () => { ) const coingeckoData = useMemo(() => { - if (!coingeckoDataQuery?.data?.length) return [] + if (!coingeckoDataQuery || !coingeckoDataQuery.length) return [] if (!flipPrices) { - return coingeckoDataQuery.data + return coingeckoDataQuery } else { - return coingeckoDataQuery.data.map((d: ChartDataItem) => { + return coingeckoDataQuery.map((d: ChartDataItem) => { const price = d.inputTokenPrice / d.outputTokenPrice === d.price ? d.outputTokenPrice / d.inputTokenPrice @@ -240,7 +244,8 @@ const SwapTokenChart = () => { }, [coingeckoData, chartSwapTimes]) const chartData = useMemo(() => { - if (!coingeckoData.length) return [] + if (!coingeckoData || !coingeckoData.length || coingeckoData.length < 2) + return [] const minTime = coingeckoData[0].time const maxTime = coingeckoData[coingeckoData.length - 1].time if (swapHistoryPoints.length && showSwaps) { @@ -274,22 +279,21 @@ const SwapTokenChart = () => { }, [inputCoingeckoId, outputCoingeckoId]) const calculateChartChange = () => { - if (chartData?.length) { - if (mouseData) { - const index = chartData.findIndex((d) => d.time === mouseData.time) - return ( - ((chartData[index]['price'] - chartData[0]['price']) / - chartData[0]['price']) * - 100 - ) - } else - return ( - ((chartData[chartData.length - 1]['price'] - chartData[0]['price']) / - chartData[0]['price']) * - 100 - ) + if (!chartData?.length) return 0 + if (mouseData) { + const index = chartData.findIndex((d) => d.time === mouseData.time) + return ( + ((chartData[index]['price'] - chartData[0]['price']) / + chartData[0]['price']) * + 100 + ) + } else { + return ( + ((chartData[chartData.length - 1]['price'] - chartData[0]['price']) / + chartData[0]['price']) * + 100 + ) } - return 0 } const swapMarketName = useMemo(() => { @@ -307,7 +311,7 @@ const SwapTokenChart = () => { return ( - {coingeckoDataQuery?.isLoading || coingeckoDataQuery.isFetching ? ( + {isLoading || isFetching ? ( <>
diff --git a/components/swap/useQuoteRoutes.ts b/components/swap/useQuoteRoutes.ts index 14c0cc43..679e7b14 100644 --- a/components/swap/useQuoteRoutes.ts +++ b/components/swap/useQuoteRoutes.ts @@ -160,8 +160,10 @@ export const handleGetRoutes = async ( routes: RouteInfo[] bestRoute: RouteInfo }[] - ).sort( - (a, b) => Number(b.bestRoute.outAmount) - Number(a.bestRoute.outAmount) + ).sort((a, b) => + swapMode === 'ExactIn' + ? Number(b.bestRoute.outAmount) - Number(a.bestRoute.outAmount) + : Number(a.bestRoute.inAmount) - Number(b.bestRoute.inAmount) ) return { routes: sortedByBiggestOutAmount[0].routes, diff --git a/components/token/CoingeckoStats.tsx b/components/token/CoingeckoStats.tsx index 05d85c71..d9346aeb 100644 --- a/components/token/CoingeckoStats.tsx +++ b/components/token/CoingeckoStats.tsx @@ -13,6 +13,7 @@ import parse from 'html-react-parser' import { useTranslation } from 'next-i18next' import { useMemo, useState } from 'react' import PriceChart from '@components/token/PriceChart' +import { DAILY_SECONDS } from 'utils/constants' dayjs.extend(relativeTime) const DEFAULT_COINGECKO_VALUES = { @@ -44,7 +45,7 @@ const fetchBirdeyePrices = async ( ): Promise => { const interval = daysToShow === '1' ? '30m' : daysToShow === '7' ? '1H' : '4H' const queryEnd = Math.floor(Date.now() / 1000) - const queryStart = queryEnd - parseInt(daysToShow) * 86400 + const queryStart = queryEnd - parseInt(daysToShow) * DAILY_SECONDS const query = `defi/history_price?address=${mint}&address_type=token&type=${interval}&time_from=${queryStart}&time_to=${queryEnd}` const response: BirdeyeResponse = await makeApiRequest(query) diff --git a/components/trade/AdvancedMarketHeader.tsx b/components/trade/AdvancedMarketHeader.tsx index bfb1cfb7..05804c97 100644 --- a/components/trade/AdvancedMarketHeader.tsx +++ b/components/trade/AdvancedMarketHeader.tsx @@ -1,6 +1,5 @@ import { PerpMarket, Serum3Market } from '@blockworks-foundation/mango-v4' import { IconButton, LinkButton } from '@components/shared/Button' -import Change from '@components/shared/Change' import { getOneDayPerpStats } from '@components/stats/PerpMarketsOverviewTable' import { ChartBarIcon, InformationCircleIcon } from '@heroicons/react/20/solid' import mangoStore from '@store/mangoStore' @@ -10,9 +9,7 @@ import { useEffect, useMemo, useState } from 'react' import { numberCompacter } from 'utils/numbers' import MarketSelectDropdown from './MarketSelectDropdown' import PerpFundingRate from './PerpFundingRate' -import { useBirdeyeMarketPrices } from 'hooks/useBirdeyeMarketPrices' import SheenLoader from '@components/shared/SheenLoader' -import usePrevious from '@components/shared/usePrevious' import PerpMarketDetailsModal from '@components/modals/PerpMarketDetailsModal' import useMangoGroup from 'hooks/useMangoGroup' import OraclePrice from './OraclePrice' @@ -23,6 +20,7 @@ import { TickerData } from 'types' import ManualRefresh from '@components/shared/ManualRefresh' import { useViewport } from 'hooks/useViewport' import { breakpoints } from 'utils/theme' +import MarketChange from '@components/shared/MarketChange' export const fetchSpotVolume = async () => { try { @@ -43,17 +41,8 @@ const AdvancedMarketHeader = ({ }) => { const { t } = useTranslation(['common', 'trade']) const perpStats = mangoStore((s) => s.perpStats.data) - const loadingPerpStats = mangoStore((s) => s.perpStats.loading) - const { - serumOrPerpMarket, - price: stalePrice, - selectedMarket, - } = useSelectedMarket() + const { serumOrPerpMarket, selectedMarket } = useSelectedMarket() const selectedMarketName = mangoStore((s) => s.selectedMarket.name) - const [changePrice, setChangePrice] = useState(stalePrice) - const { data: birdeyePrices, isLoading: loadingPrices } = - useBirdeyeMarketPrices() - const previousMarketName = usePrevious(selectedMarketName) const [showMarketDetails, setShowMarketDetails] = useState(false) const { group } = useMangoGroup() const { width } = useViewport() @@ -85,18 +74,6 @@ const AdvancedMarketHeader = ({ } }, [group]) - const birdeyeData = useMemo(() => { - if ( - !birdeyePrices?.length || - !selectedMarket || - selectedMarket instanceof PerpMarket - ) - return - return birdeyePrices.find( - (m) => m.mint === selectedMarket.serumMarketExternal.toString() - ) - }, [birdeyePrices, selectedMarket]) - const oneDayPerpStats = useMemo(() => { if ( !perpStats || @@ -108,36 +85,6 @@ const AdvancedMarketHeader = ({ return getOneDayPerpStats(perpStats, selectedMarketName) }, [perpStats, selectedMarketName]) - const change = useMemo(() => { - if ( - !changePrice || - !serumOrPerpMarket || - selectedMarketName !== previousMarketName - ) - return 0 - if (serumOrPerpMarket instanceof PerpMarket) { - return oneDayPerpStats.length - ? ((changePrice - oneDayPerpStats[0].price) / - oneDayPerpStats[0].price) * - 100 - : 0 - } else { - if (!birdeyeData) return 0 - return ( - ((changePrice - birdeyeData.data[0].value) / - birdeyeData.data[0].value) * - 100 - ) - } - }, [ - birdeyeData, - changePrice, - serumOrPerpMarket, - oneDayPerpStats, - previousMarketName, - selectedMarketName, - ]) - const perpVolume = useMemo(() => { if (!oneDayPerpStats.length) return return ( @@ -155,19 +102,13 @@ const AdvancedMarketHeader = ({
<> - +
{t('rolling-change')}
- {!loadingPrices && !loadingPerpStats ? ( - - ) : ( - -
- - )} +
{serumOrPerpMarket instanceof PerpMarket ? ( <> diff --git a/components/trade/AdvancedTradeForm.tsx b/components/trade/AdvancedTradeForm.tsx index a67a7dca..10bbbbc2 100644 --- a/components/trade/AdvancedTradeForm.tsx +++ b/components/trade/AdvancedTradeForm.tsx @@ -25,6 +25,8 @@ import NumberFormat, { NumberFormatValues, SourceInfo, } from 'react-number-format' +import * as sentry from '@sentry/nextjs' + import { notify } from 'utils/notifications' import SpotSlider from './SpotSlider' import { calculateLimitPriceForMarketOrder } from 'utils/tradeForm' @@ -454,6 +456,7 @@ const AdvancedTradeForm = () => { } } catch (e) { console.error('Place trade error:', e) + sentry.captureException(e) if (!isMangoError(e)) return notify({ title: 'There was an issue.', diff --git a/components/trade/MarketSelectDropdown.tsx b/components/trade/MarketSelectDropdown.tsx index 12882ab0..ecd38bcd 100644 --- a/components/trade/MarketSelectDropdown.tsx +++ b/components/trade/MarketSelectDropdown.tsx @@ -1,12 +1,7 @@ -// import ChartRangeButtons from '@components/shared/ChartRangeButtons' -import Change from '@components/shared/Change' import FavoriteMarketButton from '@components/shared/FavoriteMarketButton' -import SheenLoader from '@components/shared/SheenLoader' -import { getOneDayPerpStats } from '@components/stats/PerpMarketsOverviewTable' import { Popover } from '@headlessui/react' import { ChevronDownIcon } from '@heroicons/react/20/solid' import mangoStore from '@store/mangoStore' -import { useBirdeyeMarketPrices } from 'hooks/useBirdeyeMarketPrices' import useMangoGroup from 'hooks/useMangoGroup' import useSelectedMarket from 'hooks/useSelectedMarket' import { useTranslation } from 'next-i18next' @@ -23,6 +18,7 @@ import SoonBadge from '@components/shared/SoonBadge' import TabButtons from '@components/shared/TabButtons' import { PerpMarket } from '@blockworks-foundation/mango-v4' import Loading from '@components/shared/Loading' +import MarketChange from '@components/shared/MarketChange' const MARKET_LINK_WRAPPER_CLASSES = 'flex items-center justify-between px-4 md:pl-6 md:pr-4' @@ -41,11 +37,7 @@ const MarketSelectDropdown = () => { ) const serumMarkets = mangoStore((s) => s.serumMarkets) const allPerpMarkets = mangoStore((s) => s.perpMarkets) - const perpStats = mangoStore((s) => s.perpStats.data) - const loadingPerpStats = mangoStore((s) => s.perpStats.loading) const { group } = useMangoGroup() - const { data: birdeyePrices, isLoading: loadingPrices } = - useBirdeyeMarketPrices() const [spotBaseFilter, setSpotBaseFilter] = useState('All') const perpMarkets = useMemo(() => { @@ -130,14 +122,7 @@ const MarketSelectDropdown = () => {
{spotOrPerp === 'perp' && perpMarkets?.length ? perpMarkets.map((m) => { - const changeData = getOneDayPerpStats(perpStats, m.name) const isComingSoon = m.oracleLastUpdatedSlot == 0 - - const change = changeData.length - ? ((m.uiPrice - changeData[0].price) / - changeData[0].price) * - 100 - : 0 return (
{ getDecimalCount(m.tickSize) )} - {!loadingPerpStats ? ( - - ) : ( - -
- - )} +
@@ -216,12 +191,6 @@ const MarketSelectDropdown = () => { .map((x) => x) .sort((a, b) => a.name.localeCompare(b.name)) .map((m) => { - const birdeyeData = birdeyePrices?.length - ? birdeyePrices.find( - (market) => - market.mint === m.serumMarketExternal.toString() - ) - : null const baseBank = group?.getFirstBankByTokenIndex( m.baseTokenIndex ) @@ -238,12 +207,6 @@ const MarketSelectDropdown = () => { getDecimalCount(market.tickSize) ).toNumber() } - const change = - birdeyeData && price - ? ((price - birdeyeData.data[0].value) / - birdeyeData.data[0].value) * - 100 - : 0 return (
{ ) : null} ) : null} - {!loadingPrices ? ( - change ? ( - - ) : ( - - ) - ) : ( - -
- - )} +
diff --git a/components/trade/OraclePrice.tsx b/components/trade/OraclePrice.tsx index eacd8fcb..df0923f6 100644 --- a/components/trade/OraclePrice.tsx +++ b/components/trade/OraclePrice.tsx @@ -17,11 +17,7 @@ import relativeTime from 'dayjs/plugin/relativeTime' import useOracleProvider from 'hooks/useOracleProvider' import { ArrowTopRightOnSquareIcon } from '@heroicons/react/20/solid' -const OraclePrice = ({ - setChangePrice, -}: { - setChangePrice: (price: number) => void -}) => { +const OraclePrice = () => { const { serumOrPerpMarket, price: stalePrice, @@ -96,7 +92,6 @@ const OraclePrice = ({ if (selectedMarket instanceof PerpMarket) { setPrice(uiPrice) - setChangePrice(uiPrice) } else { let price if (quoteBank && serumOrPerpMarket) { @@ -108,7 +103,6 @@ const OraclePrice = ({ price = 0 } setPrice(price) - setChangePrice(price) } }, 'processed' @@ -118,14 +112,7 @@ const OraclePrice = ({ connection.removeAccountChangeListener(subId) } } - }, [ - connection, - selectedMarket, - serumOrPerpMarket, - setChangePrice, - quoteBank, - stalePrice, - ]) + }, [connection, selectedMarket, serumOrPerpMarket, quoteBank, stalePrice]) const oracleDecimals = getDecimalCount(serumOrPerpMarket?.tickSize || 0.01) diff --git a/components/trade/Orderbook.tsx b/components/trade/Orderbook.tsx index 5990440b..6d345d2b 100644 --- a/components/trade/Orderbook.tsx +++ b/components/trade/Orderbook.tsx @@ -10,7 +10,7 @@ import { formatNumericValue, getDecimalCount, } from 'utils/numbers' -import { ANIMATION_SETTINGS_KEY, USE_ORDERBOOK_FEED_KEY } from 'utils/constants' +import { ANIMATION_SETTINGS_KEY } from 'utils/constants' import { useTranslation } from 'next-i18next' import Decimal from 'decimal.js' import { OrderbookL2 } from 'types' @@ -220,11 +220,12 @@ const Orderbook = () => { const [tickSize, setTickSize] = useState(0) const [showBids, setShowBids] = useState(true) const [showAsks, setShowAsks] = useState(true) - const [useOrderbookFeed, setUseOrderbookFeed] = useState( - localStorage.getItem(USE_ORDERBOOK_FEED_KEY) !== null - ? localStorage.getItem(USE_ORDERBOOK_FEED_KEY) === 'true' - : true - ) + const [useOrderbookFeed, setUseOrderbookFeed] = useState(false) + // const [useOrderbookFeed, setUseOrderbookFeed] = useState( + // localStorage.getItem(USE_ORDERBOOK_FEED_KEY) !== null + // ? localStorage.getItem(USE_ORDERBOOK_FEED_KEY) === 'true' + // : true + // ) const currentOrderbookData = useRef() const orderbookElRef = useRef(null) diff --git a/components/trade/TradingViewChart.tsx b/components/trade/TradingViewChart.tsx index 88145e0d..c2cfda3a 100644 --- a/components/trade/TradingViewChart.tsx +++ b/components/trade/TradingViewChart.tsx @@ -88,9 +88,10 @@ const TradingViewChart = () => { const selectedMarketName = mangoStore((s) => s.selectedMarket.current?.name) const isMobile = width ? width < breakpoints.sm : false - const defaultProps = useMemo( - () => ({ - symbol: selectedMarketName, + const defaultProps = useMemo(() => { + const initialMktName = mangoStore.getState().selectedMarket.current?.name + return { + symbol: initialMktName, interval: '60' as ResolutionString, theme: 'Dark', container: 'tv_chart_container', @@ -105,9 +106,8 @@ const TradingViewChart = () => { 'volume.volume.color.1': COLORS.UP[theme], 'volume.precision': 4, }, - }), - [theme, selectedMarketName] - ) + } + }, [theme]) const tvWidgetRef = useRef() const orderLinesButtonRef = useRef() diff --git a/hooks/notifications/useNotificationSettings.ts b/hooks/notifications/useNotificationSettings.ts index ca29d3d0..60a7cfed 100644 --- a/hooks/notifications/useNotificationSettings.ts +++ b/hooks/notifications/useNotificationSettings.ts @@ -3,6 +3,7 @@ import NotificationCookieStore from '@store/notificationCookieStore' import { useWallet } from '@solana/wallet-adapter-react' import { fetchNotificationSettings } from 'apis/notifications/notificationSettings' import { useIsAuthorized } from './useIsAuthorized' +import { DAILY_MILLISECONDS } from 'utils/constants' export function useNotificationSettings() { const { publicKey } = useWallet() @@ -18,7 +19,7 @@ export function useNotificationSettings() { { enabled: !!isAuth, retry: 1, - staleTime: 86400000, + staleTime: DAILY_MILLISECONDS, } ) } diff --git a/hooks/use24HourChange.tsx b/hooks/use24HourChange.tsx new file mode 100644 index 00000000..fb56c07d --- /dev/null +++ b/hooks/use24HourChange.tsx @@ -0,0 +1,100 @@ +import { PerpMarket, Serum3Market } from '@blockworks-foundation/mango-v4' +import { getOneDayPerpStats } from '@components/stats/PerpMarketsOverviewTable' +import mangoStore from '@store/mangoStore' +import { useQuery } from '@tanstack/react-query' +import dayjs from 'dayjs' +import utc from 'dayjs/plugin/utc' +import { useMemo } from 'react' +import { DAILY_SECONDS, MANGO_DATA_API_URL } from 'utils/constants' + +dayjs.extend(utc) + +const fetchPrices = async (market: Serum3Market | PerpMarket | undefined) => { + if (!market || market instanceof PerpMarket) return + const { baseTokenIndex, quoteTokenIndex } = market + const nowTimestamp = Date.now() / 1000 + const changePriceTimestamp = nowTimestamp - DAILY_SECONDS + const changePriceTime = dayjs + .unix(changePriceTimestamp) + .utc() + .format('YYYY-MM-DDTHH:mm:ss[Z]') + const promises = [ + fetch( + `${MANGO_DATA_API_URL}/stats/token-price?token-index=${baseTokenIndex}&price-time=${changePriceTime}` + ), + fetch( + `${MANGO_DATA_API_URL}/stats/token-price?token-index=${quoteTokenIndex}&price-time=${changePriceTime}` + ), + ] + try { + const data = await Promise.all(promises) + const baseTokenPriceData = await data[0].json() + const quoteTokenPriceData = await data[1].json() + const baseTokenPrice = baseTokenPriceData ? baseTokenPriceData.price : 1 + const quoteTokenPrice = quoteTokenPriceData ? quoteTokenPriceData.price : 1 + return { baseTokenPrice, quoteTokenPrice } + } catch (e) { + console.log('failed to fetch 24hr price data', e) + return { baseTokenPrice: 1, quoteTokenPrice: 1 } + } +} + +export default function use24HourChange( + market: Serum3Market | PerpMarket | undefined +) { + const perpStats = mangoStore((s) => s.perpStats.data) + const loadingPerpStats = mangoStore((s) => s.perpStats.loading) + const { + data: priceData, + isLoading: loadingPriceData, + isFetching: fetchingPriceData, + } = useQuery(['token-prices', market], () => fetchPrices(market), { + cacheTime: 1000 * 60 * 10, + staleTime: 1000 * 60, + retry: 3, + refetchOnWindowFocus: false, + enabled: market && market instanceof Serum3Market, + }) + + const [currentBasePrice, currentQuotePrice] = useMemo(() => { + const group = mangoStore.getState().group + if (!group || !market || market instanceof PerpMarket) + return [undefined, undefined] + const baseBank = group.getFirstBankByTokenIndex(market.baseTokenIndex) + const quoteBank = group.getFirstBankByTokenIndex(market.quoteTokenIndex) + return [baseBank?.uiPrice, quoteBank?.uiPrice] + }, [market]) + + const perpChange = useMemo(() => { + if ( + !market || + market instanceof Serum3Market || + !perpStats || + !perpStats.length + ) + return + const oneDayStats = getOneDayPerpStats(perpStats, market.name) + const currentPrice = market.uiPrice + const change = oneDayStats.length + ? ((currentPrice - oneDayStats[0].price) / oneDayStats[0].price) * 100 + : undefined + return change + }, [market, perpStats]) + + const spotChange = useMemo(() => { + if (!market) return + if (!currentBasePrice || !currentQuotePrice || !priceData) return + const currentPrice = currentBasePrice / currentQuotePrice + const oneDayPrice = priceData.baseTokenPrice / priceData.quoteTokenPrice + const change = ((currentPrice - oneDayPrice) / oneDayPrice) * 100 + return change + }, [market, priceData]) + + const loading = useMemo(() => { + if (!market) return false + if (market instanceof PerpMarket) return loadingPerpStats + return loadingPriceData || fetchingPriceData + }, [market, loadingPerpStats, loadingPriceData, fetchingPriceData]) + + return { loading, perpChange, spotChange } +} diff --git a/hooks/useAccountPerformanceData.ts b/hooks/useAccountPerformanceData.ts index f8b6f0e8..3e80b815 100644 --- a/hooks/useAccountPerformanceData.ts +++ b/hooks/useAccountPerformanceData.ts @@ -3,6 +3,7 @@ import { fetchAccountPerformance } from 'utils/account' import useMangoAccount from './useMangoAccount' import { useMemo } from 'react' import { PerformanceDataItem } from 'types' +import { DAILY_MILLISECONDS } from 'utils/constants' export default function useAccountPerformanceData() { const { mangoAccountAddress } = useMangoAccount() @@ -28,7 +29,7 @@ export default function useAccountPerformanceData() { const nowDate = new Date() return performanceData.filter((d) => { const dataTime = new Date(d.time).getTime() - return dataTime >= nowDate.getTime() - 86400000 + return dataTime >= nowDate.getTime() - DAILY_MILLISECONDS }) }, [performanceData]) diff --git a/hooks/useBirdeyeMarketPrices.ts b/hooks/useBirdeyeMarketPrices.ts index 04178d20..8b2b6a72 100644 --- a/hooks/useBirdeyeMarketPrices.ts +++ b/hooks/useBirdeyeMarketPrices.ts @@ -2,6 +2,7 @@ import { Serum3Market } from '@blockworks-foundation/mango-v4' import mangoStore from '@store/mangoStore' import { useQuery } from '@tanstack/react-query' import { makeApiRequest } from 'apis/birdeye/helpers' +import { DAILY_SECONDS } from 'utils/constants' export interface BirdeyePriceResponse { address: string @@ -18,7 +19,7 @@ const fetchBirdeyePrices = async ( const promises = [] const queryEnd = Math.floor(Date.now() / 1000) - const queryStart = queryEnd - 86400 + const queryStart = queryEnd - DAILY_SECONDS for (const mint of mints) { const query = `defi/history_price?address=${mint}&address_type=pair&type=30m&time_from=${queryStart}&time_to=${queryEnd}` promises.push(makeApiRequest(query)) diff --git a/next.config.js b/next.config.js index 7e1bf3c5..16e3f90f 100644 --- a/next.config.js +++ b/next.config.js @@ -1,5 +1,6 @@ const { i18n } = require('./next-i18next.config') const webpack = require('webpack') +const { withSentryConfig } = require('@sentry/nextjs') /** @type {import('next').NextConfig} */ const nextConfig = { @@ -37,4 +38,35 @@ const nextConfig = { }, } -module.exports = nextConfig +module.exports = withSentryConfig( + nextConfig, + { + // For all available options, see: + // https://github.com/getsentry/sentry-webpack-plugin#options + + // Suppresses source map uploading logs during build + silent: true, + + org: 'mango', + project: 'mango-v4-ui', + }, + { + // For all available options, see: + // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ + + // Upload a larger set of source maps for prettier stack traces (increases build time) + widenClientFileUpload: true, + + // Transpiles SDK to be compatible with IE11 (increases bundle size) + transpileClientSDK: true, + + // Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load) + tunnelRoute: '/monitoring', + + // Hides source maps from generated client bundles + hideSourceMaps: true, + + // Automatically tree-shake Sentry logger statements to reduce bundle size + disableLogger: true, + } +) diff --git a/package.json b/package.json index 6b74d823..b6073cc2 100644 --- a/package.json +++ b/package.json @@ -21,14 +21,14 @@ "node": ">=18.x" }, "dependencies": { - "@blockworks-foundation/mango-feeds": "0.1.6", - "@blockworks-foundation/mango-v4": "^0.17.4", + "@blockworks-foundation/mango-feeds": "0.1.7", + "@blockworks-foundation/mango-v4": "^0.17.19", "@headlessui/react": "1.6.6", "@heroicons/react": "2.0.10", "@metaplex-foundation/js": "0.18.3", - "@next/font": "13.4.4", "@project-serum/anchor": "0.25.0", "@pythnetwork/client": "2.15.0", + "@sentry/nextjs": "7.58.0", "@solana/spl-governance": "0.3.27", "@solana/spl-token": "0.3.7", "@solana/wallet-adapter-base": "0.9.20", @@ -128,7 +128,8 @@ "eslint-config-next>eslint-plugin-jsx-a11y>aria-query>@babel/runtime-corejs3>core-js-pure": false, "next-i18next>core-js": false, "react-tsparticles": true, - "tsparticles>tsparticles-engine": true + "tsparticles>tsparticles-engine": true, + "@sentry/nextjs>@sentry/webpack-plugin>@sentry/cli": true } } } diff --git a/pages/api/sentry-example-api.ts b/pages/api/sentry-example-api.ts new file mode 100644 index 00000000..60dcf5a2 --- /dev/null +++ b/pages/api/sentry-example-api.ts @@ -0,0 +1,7 @@ +import { NextApiRequest, NextApiResponse } from 'next' + +// A faulty API route to test Sentry's error monitoring +export default function handler(_req: NextApiRequest, res: NextApiResponse) { + throw new Error('Sentry Example API Route Error') + res.status(200).json({ name: 'John Doe' }) +} diff --git a/pages/sentry-example-page.tsx b/pages/sentry-example-page.tsx new file mode 100644 index 00000000..fa4f3bf2 --- /dev/null +++ b/pages/sentry-example-page.tsx @@ -0,0 +1,87 @@ +import Head from 'next/head' +import * as Sentry from '@sentry/nextjs' + +export default function Home() { + return ( +
+ + Sentry Onboarding + + + +
+

+ + + +

+ +

Get started by sending us a sample error:

+ + +

+ Next, look for the error on the{' '} + + Issues Page + + . +

+

+ For more information, see{' '} + + https://docs.sentry.io/platforms/javascript/guides/nextjs/ + +

+
+
+ ) +} diff --git a/public/locales/en/common.json b/public/locales/en/common.json index e804d344..c0b0e369 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -84,7 +84,7 @@ "health-tooltip": "Projects the health of your account before you make a trade. The first value is your current account health and the second your projected account health.", "history": "History", "funding": "Funding", - "insufficient-sol": "Solana requires 0.04454 SOL rent to create a Mango Account. This will be returned if you close your account.", + "insufficient-sol": "Solana requires 0.0695 SOL rent to create a Mango Account. This will be returned if you close your account.", "interest-earned": "Interest Earned", "interest-earned-paid": "Interest Earned", "leaderboard": "Leaderboard", diff --git a/public/locales/es/common.json b/public/locales/es/common.json index e804d344..c0b0e369 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -84,7 +84,7 @@ "health-tooltip": "Projects the health of your account before you make a trade. The first value is your current account health and the second your projected account health.", "history": "History", "funding": "Funding", - "insufficient-sol": "Solana requires 0.04454 SOL rent to create a Mango Account. This will be returned if you close your account.", + "insufficient-sol": "Solana requires 0.0695 SOL rent to create a Mango Account. This will be returned if you close your account.", "interest-earned": "Interest Earned", "interest-earned-paid": "Interest Earned", "leaderboard": "Leaderboard", diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index e804d344..c0b0e369 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -84,7 +84,7 @@ "health-tooltip": "Projects the health of your account before you make a trade. The first value is your current account health and the second your projected account health.", "history": "History", "funding": "Funding", - "insufficient-sol": "Solana requires 0.04454 SOL rent to create a Mango Account. This will be returned if you close your account.", + "insufficient-sol": "Solana requires 0.0695 SOL rent to create a Mango Account. This will be returned if you close your account.", "interest-earned": "Interest Earned", "interest-earned-paid": "Interest Earned", "leaderboard": "Leaderboard", diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json index 29a8c5be..3d696ffc 100644 --- a/public/locales/zh/common.json +++ b/public/locales/zh/common.json @@ -84,7 +84,7 @@ "health-impact": "健康影响", "health-tooltip": "此在您进行交易之前预测您账户的健康状况。第一个值是您当前的帐户健康状况,第二个值是您的预测帐户健康状况。", "history": "纪录", - "insufficient-sol": "Solana需要0.04454 SOL租金才能创建Mango账户。您关闭帐户时租金将被退还。", + "insufficient-sol": "Solana需要0.0695 SOL租金才能创建Mango账户。您关闭帐户时租金将被退还。", "interest-earned": "获取利息", "interest-earned-paid": "获取利息", "leaderboard": "排行榜", diff --git a/public/locales/zh_tw/common.json b/public/locales/zh_tw/common.json index 5ae776fa..68e4b57d 100644 --- a/public/locales/zh_tw/common.json +++ b/public/locales/zh_tw/common.json @@ -84,7 +84,7 @@ "health-impact": "健康影響", "health-tooltip": "此在您進行交易之前預測您賬戶的健康狀況。第一個值是您當前的帳戶健康狀況,第二個值是您的預測帳戶健康狀況。", "history": "紀錄", - "insufficient-sol": "Solana需要0.04454 SOL租金才能創建Mango賬戶。您關閉帳戶時租金將被退還。", + "insufficient-sol": "Solana需要0.0695 SOL租金才能創建Mango賬戶。您關閉帳戶時租金將被退還。", "interest-earned": "獲取利息", "interest-earned-paid": "獲取利息", "leaderboard": "排行榜", diff --git a/public/locales/zh_tw/governance.json b/public/locales/zh_tw/governance.json index dc833087..5307c3d7 100644 --- a/public/locales/zh_tw/governance.json +++ b/public/locales/zh_tw/governance.json @@ -1,44 +1,45 @@ { - "active-proposals": "Active Proposals", - "adv-fields": "Advanced Options", + "active-proposals": "當前提案", + "adv-fields": "高級選項", "approval-q": "Approval Quorum", "base-bank": "Base Bank", "base-mint": "Base Mint", "base-token": "Base Token", - "before-listing-1": "You need at least 100,000 MNGO deposited in", - "before-listing-2": "New tokens need to have an", - "before-listing-3": "Is there sufficient liquidity?", - "before-listing-4": "New markets and tokens are approved by DAO vote. This takes 3 days", - "cancel": "Cancel", + "before-listing-1": "你必須存入10,0000 MNGO以上", + "before-listing-2": "新幣種需要有", + "before-listing-3": "是否有足夠相對USDC與SOL的流動性?", + "before-listing-4": "新幣種由DAO確認New tokens are approved by DAO vote. This takes 3 days", + "before-you-list": "提出幣種列出之前:", + "cancel": "取消", "cant-find-token-for-mint": "Can't find token for given mint", - "cant-list-oracle-not-found-pyth": "Oracle not found. Create a Pyth oracle before continuing.", - "cant-list-oracle-not-found-switch": "Oracle not found. Create a Switchboard oracle before continuing.", - "cant-list-no-openbook-market": "Openbook market not found. Create an Openbook market before continuing.", + "cant-list-no-openbook-market": "找不到Openbook市場. Create an Openbook market before continuing.", + "cant-list-oracle-not-found-pyth": "找不到預言機. Create a Pyth oracle before continuing.", + "cant-list-oracle-not-found-switch": "找不到預言機. Create a Switchboard oracle before continuing.", "connect-to-list": "Connect to list a spot market or token", - "connect-wallet": "Connect Wallet", + "connect-wallet": "連接錢包", "create": "Create", "create-market-sol-cost": "The transaction cost for listing on Openbook is ~{{cost}} SOL", "create-openbook": "Create Openbook Market", - "current-vote": "Current Vote:", - "delegate": "Delegate", - "ends": "Ends", + "current-vote": "目前狀況:", + "delegate": "委託", + "ends": "結束", "enter-valid-token-mint": "Enter a valid token mint", "error-creating-market": "Error creating market", "error-proposal-creation": "Error on proposal creation or no confirmation of transactions", "field-req": "Field is required", - "find-token": "Find Token", - "invalid-num": "Invalid Number", - "invalid-pk": "Invalid Public Key", + "find-token": "搜尋幣種", + "invalid-num": "無效的數字", + "invalid-pk": "Invalid PublicKey", "liquidity-check-error": "Error during liquidity check", - "liquidity-warning": "Low liquidity. Price impact of {{priceImpactPct}}% on a 20k USDC swap.", + "liquidity-warning": "流動性很低。 Price impact of {{priceImpactPct}}% on a 20k USDC swap.", "list-spot-market": "List Spot Market", "list-spot-market-desc": "Create a market pair from tokens listed on Mango", - "list-token": "List Token", + "list-token": "列出幣種", "list-token-desc": "List any SPL token on Mango", - "mango-governance": "Mango Governance", + "mango-governance": "Mango治理", "market-created-successful": "Market created successfully", "market-index": "Market Index", - "market-name": "Market Name", + "market-name": "市場標籤", "market-name-convention-1": "The base symbol for each token should be uppercase", "market-name-convention-2": "If either token is bridged via Portal append 'po' to the base symbol e.g. ETHpo", "market-name-convention-3": "If either token is a liquid staking derivative prepend the characters to the base symbol in lowercase e.g. mSOL", @@ -49,61 +50,61 @@ "market-pair": "Market Pair", "min-order": "Min Order Size", "mint": "Mint", - "name": "Name", - "new-listing": "New Market or Token Listing", + "name": "標籤", + "new-listing": "列出新幣種", "new-market-listing": "New Market Listing", "next": "Next", - "no": "No", + "no": "否", + "no-active-proposals": "No active proposals", "no-openbook-found": "An Openbook market is required for {{market}}", "no-openbook-found-desc": "Create an Openbook market to propose listing", - "no-active-proposals": "No Active Proposals", - "no-votes": "No Votes", - "none": "None", - "on-boarding-title": "Looks like currently connected wallet doesn't have any MNGO deposited inside realms", - "on-boarding-description": "Before you continue. Deposit at least {{amount}} MNGO into", + "no-votes": "反對票", + "none": "無", "on-boarding-deposit-info": "Your MNGO will be locked for the duration of the proposal.", + "on-boarding-description": "進行之前必須將{{amount}}MNGO以上存入帳戶", + "on-boarding-title": "Looks like currently connected wallet doesn't have any MNGO deposited inside realms", "open-book-market-id": "Openbook Market ID", - "openbook-market": "Openbook Market", + "openbook-market": "Openbook市場", "openbook-market-external": "Openbook Market External", - "openbook-market-not-found": "Openbook market not found", + "openbook-market-not-found": "找不到Openbook市場", "openbook-program": "Openbook Program", - "oracle": "Oracle", - "oracle-not-found": "Oracle not found", + "oracle": "預言機", + "oracle-not-found": "找不到預言機", "price-tick": "Tick Size", - "propose-listing": "Propose Listing", - "proposal-des": "Proposal Description", - "proposal-listed": "Your proposal to list {{token}} is live.", + "proposal-des": "提議說明", + "proposal-listed": "列出{{token}}的提議現在可以投票了", "proposal-title": "Proposal Title", - "proposals-fetch-error": "Error fetching proposals", - "pyth-oracle-error": "Error fetching Pyth oracle", + "proposals-fetch-error": "Can't fetch proposals to get free index for proposal", + "propose-listing": "Propose Listing", + "pyth-oracle-error": "Pyth oracle fetch error", "quorum-description": "Proposals must reach a minimum number of 'Yes' votes before they are eligible to pass. If the minimum is reached but there are more 'No' votes when voting ends the proposal will fail.", "quote-bank": "Quote Bank", "quote-mint": "Quote Mint", "quote-token": "Quote Token", "relinquish-vote": "Relinquish Vote", - "required-approval-achieved": "Required Approval Achieved", + "required-approval-achieved": "Required approval achieved", "select-delegate": "Select delegate", - "success": "Success!", - "switch-oracle-error": "Error fetching Switchboard oracle", + "success": "成功!", + "switch-oracle-error": "Switchboard oracle fetch error", "symbol": "Symbol", - "token-details": "Token Details", + "token-details": "幣種細節", "token-index": "Token Index", "token-mint": "Token Mint", - "tokens-deposited": "Tokens Deposited", - "token-not-found": "Token Not Found", - "use-own-wallet": "Use Own Wallet", + "token-not-found": "找不到幣種", + "tokens-deposited": "存入的幣種", + "use-own-wallet": "用自己的錢包", "view-proposal": "View Proposal", - "vote-no": "Vote No", - "vote-now": "Vote Now", - "vote-yes": "Vote Yes", - "voting-ended": "Voting Ended", - "what-happens-next": "What happens now?", + "vote-no": "投反對票", + "vote-now": "投票", + "vote-yes": "投贊成票", + "voting-ended": "投票結束", + "what-happens-next": "現在呢?", "what-happens-next-1": "Rally the voters. The voting period lasts 3 days.", "what-happens-next-2": "If your proposal passes it can be exectued when the voting period ends.", "what-happens-next-3": "{{token}} will be listed on Mango automatically on execution.", - "yes": "Yes", - "yes-votes": "Yes Votes", - "your-votes": "Your Votes:", + "yes": "是", + "yes-votes": "贊成票", + "your-votes": "你的票:", "create-switch-oracle": "Create switchboard oracle for", "estimated-oracle-cost": "Estimated cost with funding oracle for ~6 months 2.8 SOL", "create-oracle": "Create oracle", diff --git a/public/locales/zh_tw/notifications.json b/public/locales/zh_tw/notifications.json index 2632a51a..22a1b1ec 100644 --- a/public/locales/zh_tw/notifications.json +++ b/public/locales/zh_tw/notifications.json @@ -1,9 +1,9 @@ { - "clear-all": "Clear All", - "empty-state-desc": "You're all up-to-date", - "empty-state-title": "Nothing to see here", - "notifications": "Notifications", - "sign-message": "Sign Message", - "unauth-desc": "Sign with your wallet to start receiving notifications", - "unauth-title": "Notifications Inbox" + "clear-all": "清除全部", + "empty-state-desc": "都處理好了", + "empty-state-title": "這裡沒什麼", + "notifications": "通知", + "sign-message": "簽署訊息", + "unauth-desc": "連接錢包而受到通知", + "unauth-title": "通知收件匣" } \ No newline at end of file diff --git a/public/locales/zh_tw/settings.json b/public/locales/zh_tw/settings.json index c2fa321c..83ef7fe8 100644 --- a/public/locales/zh_tw/settings.json +++ b/public/locales/zh_tw/settings.json @@ -16,7 +16,7 @@ "chart-right": "圖表右", "chinese": "简体中文", "chinese-traditional": "繁體中文", - "connect-notifications": "Connect to update your notification settings", + "connect-notifications": "連接錢包來切換通知設定", "custom": "自定", "dark": "暗", "display": "顯示", @@ -86,6 +86,6 @@ "trigger-key": "Trigger Key", "transaction-fail": "交易失敗", "transaction-success": "交易成功", - "orderbook-bandwidth-saving": "Orderbook Bandwidth Saving", - "tooltip-orderbook-bandwidth-saving": "Use an off-chain service for Orderbook updates to decrease data usage by ~1000x. Disable this if open orders are not highlighted in the book correctly." + "orderbook-bandwidth-saving": "節省掛單薄頻寬", + "tooltip-orderbook-bandwidth-saving": "使用鏈下服務進行掛單簿更新,將數據使用量減少約 1000 倍。如果未結訂單在掛單簿中不正確顯示,請禁用此選項。" } \ No newline at end of file diff --git a/public/locales/zh_tw/stats.json b/public/locales/zh_tw/stats.json index 63c1c141..da7ebe31 100644 --- a/public/locales/zh_tw/stats.json +++ b/public/locales/zh_tw/stats.json @@ -1,18 +1,18 @@ { - "base-liquidation-fee": "Base Liquidation Fee", + "base-liquidation-fee": "基本清算費用", "closest-to-liquidation": "Positions Closest to Liquidation", - "daily": "Daily", - "hourly": "Hourly", + "daily": "日", + "hourly": "小時", "largest-perp-positions": "Largest Positions", "perp-details": "{{market}}統計", - "pnl-liquidation-fee": "Positive PnL Liquidation Fee", - "settle-pnl-factor": "Settle PnL Factor", - "six-hourly": "6-Hourly", - "tooltip-base-liquidation-fee": "The liqee pays this liquidation fee when a liquidator has to take over a perp base position.", - "tooltip-funding-limits": "The minimum and maximum funding rates (in percent per day).", - "tooltip-init-asset-liability-weight": "The contribution a perp position has to your initial account health. Asset weight is applied to long positions and liability weight is applied to shorts. Initial health controls your ability to withdraw and open new positions and is shown as an account's free collateral.", - "tooltip-maint-asset-liability-weight": "The contribution a perp position has to your maintenance account health. Asset weight is applied to long positions and liability weight is applied to shorts. Maintenance health is what's displayed on your account page. If this value reaches zero your account will be liquidated.", - "tooltip-pnl-liquidation-fee": "The liqee pays this liquidation fee when a liquidator has to take over positive unsettled perp pnl.", - "tooltip-settle-pnl-factor": "As an exploit mitigation, settlement of unrealized pnl is limited to this multiple of perp notional value in each time period.", - "volume": "Volume" + "pnl-liquidation-fee": "正數盈虧清算費用", + "settle-pnl-factor": "結清盈虧因素", + "six-hourly": "6-小時", + "tooltip-base-liquidation-fee": "當清算者接管持倉時,被清算者將支付此費用。", + "tooltip-funding-limits": "資金費用的最高與最低(一天)。", + "tooltip-init-asset-liability-weight": "永續合約對您初始賬戶健康狀況的貢獻。資產權重適用於多頭持倉,債務權重適用於空頭持倉。初始健康狀況控制您提取和開立新持倉的能力,並顯示為賬戶的可用抵押品。", + "tooltip-maint-asset-liability-weight": "永續合約對您維護賬戶健康狀況的貢獻。資產權重適用於多頭持倉,債務權重適用於空頭持倉。維護健康狀況在您帳戶頁面上顯示。如果該值達到零,您的帳戶將被清算。", + "tooltip-pnl-liquidation-fee": "當清算者接管有未結算正盈虧的持倉時,被清算者將支付此費用。", + "tooltip-settle-pnl-factor": "作為一種漏洞緩解措施,未實現盈虧的結算僅限於每個時間段內名義價值的倍數。", + "volume": "交易量" } \ No newline at end of file diff --git a/public/locales/zh_tw/swap.json b/public/locales/zh_tw/swap.json index 12b86454..b2520af2 100644 --- a/public/locales/zh_tw/swap.json +++ b/public/locales/zh_tw/swap.json @@ -1,8 +1,8 @@ { "confirm-swap": "確定換幣", "connect-swap": "連接來查換幣紀錄", - "disabled": "Disabled", - "enabled": "Enabled", + "disabled": "關閉", + "enabled": "開啟", "est-liq-price": "預計清算價格", "fees-paid-to": "繳給{{route}}的費用", "health-impact": "健康影響", @@ -11,7 +11,7 @@ "input-reduce-only-warning": "{{symbol}}處於僅減少模式。您可以將餘額換成另一個幣種", "insufficient-balance": "{{symbol}}餘額不夠", "insufficient-collateral": "質押品不夠", - "margin": "Margin", + "margin": "保證金", "margin-swap": "槓桿換幣", "max-slippage": "最多下滑", "maximum-cost": "最大成本", @@ -27,7 +27,7 @@ "receive": "你將獲取", "received": "獲取", "review-swap": "檢視換幣", - "route-info": "Route Info", + "route-info": "路線細節", "show-fees": "顯示費用", "show-swap-history": "顯示換幣紀錄–價格來自CoinGecko而也許跟換幣價格不同", "slippage": "下滑", @@ -38,7 +38,7 @@ "swap-route": "換幣路線", "tooltip-borrow-balance": "您將使用您的 {{balance}} {{token}} 餘額並借入 {{borrowAmount}} {{token}} 來執行此交換。當前的 {{token}} 可變借貸利率為 {{rate}}%", "tooltip-borrow-no-balance": "您將借入 {{borrowAmount}} {{token}} 來執行此交換。當前的 {{token}} 可變借貸利率為 {{rate}}%", - "tooltip-margin": "When margin is enabled you can add leverage to your swaps. Borrows are opened automatically if a swap exceeds your balance.", + "tooltip-margin": "啟用保證金時將能槓桿換幣。如果換幣數量超過您的餘額將會自動借款。", "tooltip-max-slippage": "如果價格下滑超過您的最大滑點,換幣交易將不會被執行", "use-margin": "允許槓桿" } \ No newline at end of file diff --git a/public/locales/zh_tw/token.json b/public/locales/zh_tw/token.json index 430b94b1..406790b5 100644 --- a/public/locales/zh_tw/token.json +++ b/public/locales/zh_tw/token.json @@ -7,43 +7,43 @@ "borrows": "借貸", "chart-unavailable": "無法顯示圖表", "circulating-supply": "流通供應量", - "deposit-borrow-scaling-start": "Deposit/Borrow Scaling Start", + "deposit-borrow-scaling-start": "存款/借款縮放起點", "deposit-rates": "存款利率", "deposits": "存款", "fdv": "全稀釋市值", "fees-tooltip": "為貸款發放、貸款維護和Openbook收取的費用。", "go-to-account": "檢視帳戶", - "init-asset-liability-weight": "Init Asset/Liability Weight", - "insurance-rate-curve": "Insurance Rate Curve", + "init-asset-liability-weight": "初始資產/債務權重", + "insurance-rate-curve": "保險率曲線", "lending": "借出", - "maint-asset-liability-weight": "Maint Asset/Liability Weight", + "maint-asset-liability-weight": "維持資產/債務權重", "market-cap": "總市值", "max-supply": "最大供應量", - "net-borrow-limit-in-period": "Net Borrow Limit in Period", - "net-borrow-period": "Net Borrow Period", - "net-borrows-in-period": "Net Borrows in Period", + "net-borrow-limit-in-period": "當期淨借貸限額", + "net-borrow-period": "淨借貸時期", + "net-borrows-in-period": "當期淨借貸", "no-borrowers": "無借貸者...", "no-depositors": "無存款者...", - "oracle": "Oracle", - "oracle-confidence": "Oracle Confidence", - "oracle-staleness": "Oracle Staleness", - "parameters": "Parameters", + "oracle": "預言機", + "oracle-confidence": "預言機可信度", + "oracle-staleness": "預言機不新鮮性", + "parameters": "參數", "token-stats": "幣種細節", - "token-fees-collected": "Token Fees Collected", + "token-fees-collected": "收取的幣種費用", "token-not-found": "查不到幣種", "token-not-found-desc": "'{{token}}'未列入或我們在加載數據時出錯。", - "tooltip-borrow-upkeep-rate": "The yearly rate paid to the DAO on open borrows. This is included in the displayed borrow interest rate.", - "tooltip-deposit-borrow-scaling-start": "This acts as a soft limit for deposits and borrows. For deposits, if this value is exceeded the asset weight for deposits is scaled down. For borrows, the liability weight for borrows is scaled up.", - "tooltip-init-asset-liability-weight": "The contribution a token has to your initial account health. Asset weight is applied to deposits that increase health and liability weight is applied to borrows that reduce it. Initial health controls your ability to withdraw and open new positions and is shown as an account's free collateral.", - "tooltip-insurance-rate-curve": "Interest rates are dependent on token utilization. The more tokens that are lent out the higher the rate. The curve scales up and down with long term trends in utilization.", - "tooltip-liquidation-fee": "The fee paid to liqudators for liquidating {{symbol}}.", - "tooltip-maint-asset-liability-weight": "The contribution a token has to your maintenance account health. Asset weight is applied to deposits that increase health and liability weight is applied to borrows that reduce it. Maintenance health is what's displayed on your account page. If this value reaches zero your account will be liquidated.", - "tooltip-net-borrow-period": "As a safety feature, the amount of new borrows is limited. The limit resets at regular periods. This is the amount of time between resets.", - "tooltip-net-borrow-limit-in-period": "The maximum value of allowed net borrows. Once this value is reached, new borrows will be disabled until the end of the period.", - "tooltip-net-borrows-in-period": "Current value of net borrows (borrows - repayments) in this period.", - "tooltip-oracle-confidence": "Oracles work by aggregating multiple price sources. If these sources disagree too much, confidence will be low. If it's below this threshold, the price is considered invalid.", - "tooltip-oracle-staleness": "Price is considered valid when it is last updated within {{slots}} slots.", - "tooltip-token-fees-collected": "These fees accrue in every native token listed on Mango. The values in this chart are derived from the current market value.", + "tooltip-borrow-upkeep-rate": "支付給 DAO 的借貸年利率。這包含在顯示的借貸利率中。", + "tooltip-deposit-borrow-scaling-start": "這作為存款和借款的軟限制。對於存款,如果超過此值資產權重將降低。對於借款,負債權重將增加。", + "tooltip-init-asset-liability-weight": "幣種對您帳戶的初始健康度的貢獻。資產權重會影響任何增加健康度的存款,負債權重會影響任何降低健康度的借貸。初始健康度控制您提款以及開倉的能力,並顯示為賬戶的可用的質押品。", + "tooltip-insurance-rate-curve": "利率受幣種利用率的影響。借出的幣種越多利率就越高。曲線按照利用率的長期趨勢而波動。", + "tooltip-liquidation-fee": "支付給清算者清算 {{symbol}} 的費用。", + "tooltip-maint-asset-liability-weight": "幣種對您帳戶的維持健康度的貢獻。資產權重會影響任何增加健康度的存款,負債權重會影響任何降低健康度的借貸。 維持健康狀況顯示在您的帳戶頁面上。如果此值達到零,您的帳戶將被清算。", + "tooltip-net-borrow-period": "作為一項安全功能,新借貸的數量是有限的。限制會定期重置。這是重置期間。", + "tooltip-net-borrow-limit-in-period": "允許的淨借袋的最大值。一旦達到此值,新借入將被禁用,直到該期間結束。", + "tooltip-net-borrows-in-period": "本期淨借袋(借款減還款)的現值。", + "tooltip-oracle-confidence": "預言機會將多個價格來源做比較。如果這些價格的分歧太大,信心度就會降低。如果低於此參數,則價格被視為無效。", + "tooltip-oracle-staleness": "價格在{{slots}}個時段內更新將被視為有效。", + "tooltip-token-fees-collected": "這些費用在 Mango 上列出的所有幣種中都會累積。此圖表中的值來自當前市場價值。", "top-borrowers": "頂級{{symbol}}借貸者", "top-depositors": "頂級{{symbol}}存款者", "total-supply": "總供應量", diff --git a/public/locales/zh_tw/trade.json b/public/locales/zh_tw/trade.json index 60dc6b37..bed218e9 100644 --- a/public/locales/zh_tw/trade.json +++ b/public/locales/zh_tw/trade.json @@ -1,70 +1,71 @@ { - "24h-volume": "24h Volume", - "activate-volume-alert": "Activate Volume Alert", - "amount": "Amount", - "average-funding": "Average {{interval}} Funding", - "base": "Base", - "book": "Book", - "buys": "Buys", - "cancel-order-error": "Failed to cancel order", - "close-confirm": "Market close your {{config_name}} position", - "close-position": "Close Position", - "connect-orders": "Connect to view your open orders", - "connect-positions": "Connect to view your perp positions", - "connect-trade-history": "Connect to view your trade history", - "connect-unsettled": "Connect to view your unsettled funds", - "copy-and-share": "Copy Image to Clipboard", - "current-price": "Current Price", - "edit-order": "Edit Order", - "est-liq-price": "Est. Liq. Price", - "avg-entry-price": "Avg. Entry Price", - "est-slippage": "Est. Slippage", - "funding-limits": "Funding Limits", - "funding-rate": "1h Avg Funding Rate", - "grouping": "Grouping", - "hide-asks": "Hide Asks", - "hide-bids": "Hide Bids", - "in-orders": "In Orders", - "init-leverage": "Init Leverage", - "instantaneous-funding": "Instantaneous Funding Snapshot", - "interval-seconds": "Interval (seconds)", - "insured": "{{token}} Insured", - "last-updated": "Last updated", - "limit": "Limit", + "24h-volume": "24小時交易量", + "activate-volume-alert": "啟動交易量鬧鐘", + "amount": "數量", + "average-funding": "平均 {{interval}} 資金費", + "avg-entry-price": "平均開倉價格", + "base": "基礎", + "book": "單薄", + "buys": "買", + "cancel-order-error": "取消訂單失敗", + "close-confirm": "市場平倉 {{config_name}}", + "close-position": "平倉", + "connect-orders": "連接以查看未結訂單", + "connect-positions": "連接以查看持倉", + "connect-trade-history": "連接以查看交易歷史", + "connect-unsettled": "連接以查看未結清餘額", + "copy-and-share": "將圖片複製到剪貼版", + "current-price": "目前價格", + "edit-order": "編輯訂單", + "est-liq-price": "預計清算價格", + "est-slippage": "預計下滑", + "funding-limits": "資金費限制", + "funding-rate": "1小時平均資金費", + "grouping": "分組", + "hide-asks": "隱藏要價", + "hide-bids": "隱藏出價", + "in-orders": "在訂單內", + "init-leverage": "初始槓桿率", + "instantaneous-funding": "瞬時資金費率", + "insured": "{{token}} 受保險", + "interval-seconds": "時間間隔 (秒)", + "last-updated": "最近更新", + "limit": "限價", "limit-price": "限價價格", "long": "做多", "maker": "掛單者", - "maker-fee": "掛單者 Fee", + "maker-fee": "掛單者費用", "margin": "保證金", - "market": "Market", + "market": "市場", "market-details": "{{market}}市場細節", "max-leverage": "最多槓桿", "min-order-size": "最小訂單量", - "min-order-size-error": "Min order size is {{minSize}} {{symbol}}", - "more-details": "More Details", - "no-balances": "No balances", - "no-orders": "No open orders", - "no-positions": "No perp positions", - "no-unsettled": "No unsettled funds", - "notional": "Notional", - "notional-volume": "Notional Volume ($)", - "open-interest": "Open Interest", - "oracle": "Oracle", - "oracle-not-updated": "This oracle has not updated recently.", - "oracle-not-updated-warning": "Actions will fail for accounts with a position in this token.", - "oracle-price": "Oracle Price", - "order-error": "Failed to place order", - "order-type": "Order Type", - "order-value": "Order Value", - "orders": "Orders", - "place-order": "Place {{side}} Order", - "placing-order": "Placing Order", - "positions": "Positions", + "min-order-size-error": "訂單的最小數量是 {{minSize}} {{symbol}}", + "more-details": "看細節", + "no-balances": "無餘額", + "no-orders": "無訂單", + "no-positions": "無持倉", + "no-unsettled": "無未結清餘額", + "notional": "名義", + "notional-volume": "名義交易量($)", + "open-interest": "未平倉", + "oracle": "預言機", + "oracle-not-updated": "此預言機最近沒更新。", + "oracle-not-updated-warning": "有該幣種持倉的賬戶,操作將會失敗。", + "oracle-price": "預言機價格", + "order-error": "下單失敗", + "order-type": "訂單種類", + "order-value": "訂單價值", + "orders": "訂單", + "place-order": "下{{side}}單", + "placing-order": "正在下單", + "positions": "持倉", "post": "Post", "preview-sound": "聲音預覽", "price-expect": "您收到的價格可能與您預期有差異,並且無法保證完全執行。為了您的安全,最大滑點保持為 2.5%。超過 2.5%滑點的部分不會被平倉。", - "price-provided-by": "語言機來自", + "price-provided-by": "預言機來自", "quote": "計價", + "realized-pnl": "已實現的盈虧", "reduce": "Reduce", "reduce-only": "限減少", "sells": "賣單", @@ -78,25 +79,24 @@ "spread": "差價", "stable-price": "穩定價格", "taker": "吃單者", - "taker-fee": "吃單者 Fee", + "taker-fee": "吃單者費用", "tick-size": "波動單位", - "realized-pnl": "Realized PnL", - "tooltip-borrow-balance": "You'll use your {{balance}} {{token}} balance and borrow {{borrowAmount}} {{token}} to execute this trade. The current {{token}} variable borrow rate is {{rate}}%", - "tooltip-borrow-no-balance": "You'll borrow {{borrowAmount}} {{token}} to execute this trade. The current {{token}} variable borrow rate is {{rate}}%", - "tooltip-enable-margin": "Enable spot margin for this trade", - "tooltip-est-liq-price": "Estimated liquidation price is calculated in isolation and does not factor price changes in other markets/tokens.", - "tooltip-ioc": "Immediate-Or-Cancel (IOC) orders are guaranteed to be the taker and must be executed immediately. Any portion of the order that can't be filled immediately will be cancelled", - "tooltip-insured": "Whether or not {{tokenOrMarket}} losses can be recovered from the insurance fund in the event of bankruptcies.", - "tooltip-post": "Post orders are guaranteed to be the maker or they will be canceled", - "tooltip-slippage": "An estimate of the difference between the current price and the price your trade will be executed at", - "tooltip-volume-alert": "Volume Alert Settings", - "tooltip-stable-price": "Stable price is used in a safety mechanism that limits a user's ability to enter risky positions when the oracle price is changing rapidly", - "total-pnl": "Total PnL", - "trade-sounds-tooltip": "Play a sound alert for every new trade", - "trades": "Trades", - "tweet-position": "Tweet", - "unrealized-pnl": "Unrealized PnL", - "unsettled": "Unsettled", - "volume-alert": "Volume Alert", - "volume-alert-desc": "Play a sound whenever volume exceeds your alert threshold" + "tooltip-borrow-balance": "您將使用您的 {{balance}} {{token}} 餘額並藉入 {{borrowAmount}} {{token}} 來執行此交易。當前的 {{token}} 可變借貸利率為 {{rate}}%", + "tooltip-borrow-no-balance": "你將借{{borrowAmount}} {{token}}來成交。{{token}} 的可變的借貸利率為 {{rate}}%", + "tooltip-enable-margin": "為此交易啟用保證金", + "tooltip-est-liq-price": "預計清算價格是單獨計算的,不考慮其他市場/幣種的價格變化。", + "tooltip-insured": "如果發生破產,{{tokenOrMarket}}損失是否可以從保險基金中歸還", + "tooltip-ioc": "IOC交易若不吃單就會被取消。任何無法立刻成交的部分將被取消", + "tooltip-post": "Post交易若不掛單就會被取消。", + "tooltip-slippage": "當前價格與您的交易將執行的價格之間的差值的估計", + "tooltip-stable-price": "穩定價格用於一個安全機制。此機制可以限制用戶在預言機價格快速波動時下風險高的訂單", + "tooltip-volume-alert": "交易量警報設定", + "total-pnl": "總盈虧", + "trade-sounds-tooltip": "為每筆新交易播放警報聲音", + "trades": "交易", + "tweet-position": "分享至Twitter", + "unrealized-pnl": "未實現盈虧", + "unsettled": "未結清", + "volume-alert": "交易量警報", + "volume-alert-desc": "交易量超過警報設定時播放聲音" } \ No newline at end of file diff --git a/sentry.client.config.ts b/sentry.client.config.ts new file mode 100644 index 00000000..ce156ea2 --- /dev/null +++ b/sentry.client.config.ts @@ -0,0 +1,32 @@ +// This file configures the initialization of Sentry on the client. +// The config you add here will be used whenever a users loads a page in their browser. +// https://docs.sentry.io/platforms/javascript/guides/nextjs/ + +import * as Sentry from '@sentry/nextjs' + +const SENTRY_DSN = process.env.NEXT_PUBLIC_SENTRY_DSN + +Sentry.init({ + dsn: SENTRY_DSN, + + // Adjust this value in production, or use tracesSampler for greater control + tracesSampleRate: 1, + + // Setting this option to true will print useful information to the console while you're setting up Sentry. + debug: false, + + replaysOnErrorSampleRate: 1.0, + + // This sets the sample rate to be 10%. You may want this to be 100% while + // in development and sample at a lower rate in production + replaysSessionSampleRate: 0.1, + + // You can remove this option if you're not planning to use the Sentry Session Replay feature: + integrations: [ + new Sentry.Replay({ + // Additional Replay configuration goes in here, for example: + maskAllText: true, + blockAllMedia: true, + }), + ], +}) diff --git a/sentry.edge.config.ts b/sentry.edge.config.ts new file mode 100644 index 00000000..137c1b11 --- /dev/null +++ b/sentry.edge.config.ts @@ -0,0 +1,16 @@ +// This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on). +// The config you add here will be used whenever one of the edge features is loaded. +// Note that this config is unrelated to the Vercel Edge Runtime and is also required when running locally. +// https://docs.sentry.io/platforms/javascript/guides/nextjs/ + +import * as Sentry from '@sentry/nextjs' +const SENTRY_DSN = process.env.NEXT_PUBLIC_SENTRY_DSN +Sentry.init({ + dsn: SENTRY_DSN, + + // Adjust this value in production, or use tracesSampler for greater control + tracesSampleRate: 1, + + // Setting this option to true will print useful information to the console while you're setting up Sentry. + debug: false, +}) diff --git a/sentry.server.config.ts b/sentry.server.config.ts new file mode 100644 index 00000000..f37d7b53 --- /dev/null +++ b/sentry.server.config.ts @@ -0,0 +1,16 @@ +// This file configures the initialization of Sentry on the server. +// The config you add here will be used whenever the server handles a request. +// https://docs.sentry.io/platforms/javascript/guides/nextjs/ + +import * as Sentry from '@sentry/nextjs' +const SENTRY_DSN = process.env.NEXT_PUBLIC_SENTRY_DSN + +Sentry.init({ + dsn: SENTRY_DSN, + + // Adjust this value in production, or use tracesSampler for greater control + tracesSampleRate: 1, + + // Setting this option to true will print useful information to the console while you're setting up Sentry. + debug: false, +}) diff --git a/store/mangoStore.ts b/store/mangoStore.ts index f5fce086..6e92066c 100644 --- a/store/mangoStore.ts +++ b/store/mangoStore.ts @@ -328,7 +328,7 @@ const mangoStore = create()( details: { profile_name: '', trader_category: '', wallet_pk: '' }, }, selectedMarket: { - name: '', + name: 'SOL/USDC', current: undefined, fills: [], bidsAccount: undefined, diff --git a/utils/constants.ts b/utils/constants.ts index f35609d2..ab006c88 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -43,7 +43,7 @@ export const FAVORITE_MARKETS_KEY = 'favoriteMarkets-0.2' export const THEME_KEY = 'theme-0.1' -export const RPC_PROVIDER_KEY = 'rpcProviderKey-0.5' +export const RPC_PROVIDER_KEY = 'rpcProviderKey-0.6' export const PRIORITY_FEE_KEY = 'priorityFeeKey-0.1' @@ -131,3 +131,5 @@ export const CUSTOM_TOKEN_ICONS: { [key: string]: boolean } = { } export const WHITE_LIST_API = 'https://api.mngo.cloud/whitelist/v1/' +export const DAILY_SECONDS = 86400 +export const DAILY_MILLISECONDS = 86400000 diff --git a/utils/fonts.ts b/utils/fonts.ts index 5dad22f5..2254ed8e 100644 --- a/utils/fonts.ts +++ b/utils/fonts.ts @@ -1,4 +1,4 @@ -import localFont from '@next/font/local' +import localFont from 'next/font/local' export const ttCommons = localFont({ src: [ diff --git a/yarn.lock b/yarn.lock index aef37c23..c821f7a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14,17 +14,17 @@ dependencies: regenerator-runtime "^0.13.11" -"@blockworks-foundation/mango-feeds@0.1.6": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-feeds/-/mango-feeds-0.1.6.tgz#ae82a0f1cb131633b7edd76e2397cfd486cd21c0" - integrity sha512-vsulzORXp8Qyd74ogm809UxxiiL2Gr9UmcxHMeYpd8tohVHLcFF6+SGKmX/9ImSElBrw+zEKIzY5O50w/QM7mQ== +"@blockworks-foundation/mango-feeds@0.1.7": + version "0.1.7" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-feeds/-/mango-feeds-0.1.7.tgz#07283e4f6b52ce2e631b866f7675b395dcc15f9e" + integrity sha512-wvHYCgZ+mp0kJs5UDkLoTOVnLyhDGG4BFkF2efn1t8MJP6H2fMUMmMn41I6C6LdjAv0Rz54nGoQxp6nE45yBhQ== dependencies: ws "^8.13.0" -"@blockworks-foundation/mango-v4@^0.17.4": - version "0.17.4" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4/-/mango-v4-0.17.4.tgz#49a4bc763ecf5558a3fbedcba2587984c882af4b" - integrity sha512-0T5uQtSoCilET2CB0tXzORJpLZatqFMxilRhhIK2jVsupAaoG/08ZXoDNzA6y2WWZHqbvfkGkLYonH24MAibhw== +"@blockworks-foundation/mango-v4@^0.17.19": + version "0.17.19" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4/-/mango-v4-0.17.19.tgz#63a7bb62022b71a80eb2c654983af9a0347fac5a" + integrity sha512-L9BEsiXOK/dYAC+1MZ1T+7bmf3y3zK8yST2+EQqP7UEhvcy5dk/oHDjEQ7iSm9LcofpJD1OgE3tfVbn7yPttPQ== dependencies: "@coral-xyz/anchor" "^0.27.0" "@project-serum/serum" "0.13.65" @@ -530,10 +530,10 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" @@ -860,11 +860,6 @@ dependencies: glob "7.1.7" -"@next/font@13.4.4": - version "13.4.4" - resolved "https://registry.yarnpkg.com/@next/font/-/font-13.4.4.tgz#513632591a1041e39c1020022c0995ca78dde4fc" - integrity sha512-iYmL/O0rV9NS8a2UXuRoZOzImz8Q0mM8bAmxtj8nccrpwZ6iOOZlbf2d0Genczl4wtuXRXVPR8goGjJM4C2SDg== - "@next/swc-darwin-arm64@13.4.4": version "13.4.4" resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.4.tgz#8c14083c2478e2a9a8d140cce5900f76b75667ff" @@ -1192,11 +1187,158 @@ dependencies: merge-options "^3.0.4" +"@rollup/plugin-commonjs@24.0.0": + version "24.0.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.0.tgz#fb7cf4a6029f07ec42b25daa535c75b05a43f75c" + integrity sha512-0w0wyykzdyRRPHOb0cQt14mIBLujfAv6GgP6g8nvg/iBxEm112t3YPPq+Buqe2+imvElTka+bjNlJ/gB56TD8g== + dependencies: + "@rollup/pluginutils" "^5.0.1" + commondir "^1.0.1" + estree-walker "^2.0.2" + glob "^8.0.3" + is-reference "1.2.1" + magic-string "^0.27.0" + +"@rollup/pluginutils@^5.0.1": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33" + integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^2.3.1" + "@rushstack/eslint-patch@^1.1.3": version "1.2.0" resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz#8be36a1f66f3265389e90b5f9c9962146758f728" integrity sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg== +"@sentry-internal/tracing@7.58.0": + version "7.58.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.58.0.tgz#f6494ae212644b6d268decee6b660d9789b8db9a" + integrity sha512-7V/vkFFYCmSq25er3Y0wukkTM940Wvk9qjh7kWcCCeesKFHNGBCP7HVZhsymjPIJGGJTvRWc9MgBzRGe/c16Xg== + dependencies: + "@sentry/core" "7.58.0" + "@sentry/types" "7.58.0" + "@sentry/utils" "7.58.0" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/browser@7.58.0": + version "7.58.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.58.0.tgz#75f6f0a39435327ec95ef38722161336ba9ded79" + integrity sha512-v+PaTuK4LOJ1/uAxNQHUMRLWdlIOdiKlZAgoZojixdFKajHAeguzok93d0u2SZJaGDaLmkJYSiGAPBs1d1jHhA== + dependencies: + "@sentry-internal/tracing" "7.58.0" + "@sentry/core" "7.58.0" + "@sentry/replay" "7.58.0" + "@sentry/types" "7.58.0" + "@sentry/utils" "7.58.0" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/cli@^1.74.6": + version "1.75.2" + resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.75.2.tgz#2c38647b38300e52c9839612d42b7c23f8d6455b" + integrity sha512-CG0CKH4VCKWzEaegouWfCLQt9SFN+AieFESCatJ7zSuJmzF05ywpMusjxqRul6lMwfUhRKjGKOzcRJ1jLsfTBw== + dependencies: + https-proxy-agent "^5.0.0" + mkdirp "^0.5.5" + node-fetch "^2.6.7" + progress "^2.0.3" + proxy-from-env "^1.1.0" + which "^2.0.2" + +"@sentry/core@7.58.0": + version "7.58.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.58.0.tgz#5d800342225bb8a168635c13d27b2e2119dc0b0f" + integrity sha512-tdz+HOh9blnfJ4ZSfsaVaSh/i7pD2QfmC0///fWlNm+IvD+SAgYFP6M3PIsJMsaN5heZ9XMNY4wnxvd+vvJwPQ== + dependencies: + "@sentry/types" "7.58.0" + "@sentry/utils" "7.58.0" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/integrations@7.58.0": + version "7.58.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.58.0.tgz#872229179e9b3a9f3e0b974f125405f7d0a0cdec" + integrity sha512-SaXGUb7R35/bh4mGJzB0+7kZGFfoGkd32NMQzCv1DcSyglPD/LFCf2Gq5QTleFJWxPERZemLwn+NBeCKHy6iPw== + dependencies: + "@sentry/types" "7.58.0" + "@sentry/utils" "7.58.0" + localforage "^1.8.1" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/nextjs@7.58.0": + version "7.58.0" + resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.58.0.tgz#240bd4e9b6bdd81641352607380f2fc5a6b396e8" + integrity sha512-t2RKUVAZxSpJnUFcZMcBsh2iy72/5pWkwXDtnIaXUntQ5uwpqA0ZwWCOPp6kd1o+s9XhE8v+WLpIL6rXo67ZEg== + dependencies: + "@rollup/plugin-commonjs" "24.0.0" + "@sentry/core" "7.58.0" + "@sentry/integrations" "7.58.0" + "@sentry/node" "7.58.0" + "@sentry/react" "7.58.0" + "@sentry/types" "7.58.0" + "@sentry/utils" "7.58.0" + "@sentry/webpack-plugin" "1.20.0" + chalk "3.0.0" + rollup "2.78.0" + stacktrace-parser "^0.1.10" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/node@7.58.0": + version "7.58.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.58.0.tgz#0e95a593f0a6b7a4cf46913ec7343f10397042da" + integrity sha512-Br6l0XuBEI13dektlPi0jvaVrUEirL7Z61SvbdjR8C/G6O9TXw0wKwc/BXf1GYV5JP7jsWHdRQEO2s45mtmNwQ== + dependencies: + "@sentry-internal/tracing" "7.58.0" + "@sentry/core" "7.58.0" + "@sentry/types" "7.58.0" + "@sentry/utils" "7.58.0" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/react@7.58.0": + version "7.58.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.58.0.tgz#2d40af026374371bcc0ecf0b1b3429ba83f26aa6" + integrity sha512-TCKZd1v7CPpdjvT2S6naA85e/X8MonU7vR4vCJiVRiK08XBn3qDt4kGa0yrB20GLxJQ+RHW1WURUdS8MM1D9Pg== + dependencies: + "@sentry/browser" "7.58.0" + "@sentry/types" "7.58.0" + "@sentry/utils" "7.58.0" + hoist-non-react-statics "^3.3.2" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/replay@7.58.0": + version "7.58.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.58.0.tgz#aa2499f1cbff82b27ec370d8ff0b5b6b64fb058e" + integrity sha512-gzanY+Y+48ErQxFWl2t031awz/4fR6v0Pkvu7mZWl8ZraLiVRqk2T7aPyxcL2I7yFwFElJ6mZw7buce+R+IaTA== + dependencies: + "@sentry/core" "7.58.0" + "@sentry/types" "7.58.0" + "@sentry/utils" "7.58.0" + +"@sentry/types@7.58.0": + version "7.58.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.58.0.tgz#d74e5c6cb7bfd0b98d561fc99d12f76d904c6496" + integrity sha512-uy8rww5R0WSxr9kB1R1BXWomkKXosK+jOFslbIda4CfTiAMEINi7rXkqTzPJKCIRLHFvKXDFUIkMCHNMkgYjwA== + +"@sentry/utils@7.58.0": + version "7.58.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.58.0.tgz#645ae4fdfe2af2d7020e895aa449e7c7dcd77442" + integrity sha512-EAknRDovGBnIVvGLJVxPbB1gUY/VCUoVov26Fk1BYLtUmWlzt+JYHsBJptHw15onu+M0em7z7Iax4wKoiNhhzA== + dependencies: + "@sentry/types" "7.58.0" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/webpack-plugin@1.20.0": + version "1.20.0" + resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-1.20.0.tgz#e7add76122708fb6b4ee7951294b521019720e58" + integrity sha512-Ssj1mJVFsfU6vMCOM2d+h+KQR7QHSfeIP16t4l20Uq/neqWXZUQ2yvQfe4S3BjdbJXz/X4Rw8Hfy1Sd0ocunYw== + dependencies: + "@sentry/cli" "^1.74.6" + webpack-sources "^2.0.0 || ^3.0.0" + "@socket.io/component-emitter@~3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" @@ -2226,6 +2368,11 @@ resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.0.tgz#e2505f1c21ec08bda8915238e397fb71d2fc54ce" integrity sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g== +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" + integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== + "@types/hoist-non-react-statics@^3.3.1": version "3.3.1" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" @@ -3634,6 +3781,14 @@ chai@^4.3.7: pathval "^1.1.1" type-detect "^4.0.5" +chalk@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -3786,6 +3941,11 @@ commander@^8.2.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -3796,6 +3956,11 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== +cookie@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + copy-to-clipboard@^3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" @@ -4783,6 +4948,11 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -5239,6 +5409,17 @@ glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^8.0.3: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + globals@^13.19.0, globals@^13.6.0: version "13.20.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" @@ -5521,6 +5702,11 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + immer@9.0.12: version "9.0.12" resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.12.tgz#2d33ddf3ee1d247deab9d707ca472c8c942a0f20" @@ -5741,6 +5927,13 @@ is-plain-obj@^3.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== +is-reference@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" + integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== + dependencies: + "@types/estree" "*" + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -6050,11 +6243,25 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== + dependencies: + immediate "~3.0.5" + lilconfig@^2.0.5, lilconfig@^2.0.6: version "2.1.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== +localforage@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== + dependencies: + lie "3.1.1" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -6146,6 +6353,18 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru_map@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" + integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== + +magic-string@^0.27.0: + version "0.27.0" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3" + integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.13" + make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -6250,6 +6469,13 @@ minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -6275,6 +6501,13 @@ minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" +mkdirp@^0.5.5: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + mkdirp@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" @@ -6966,6 +7199,11 @@ process@0.11.10, process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== +progress@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + prop-types@15.x, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" @@ -7490,6 +7728,13 @@ rlp@^2.2.4: dependencies: bn.js "^5.2.0" +rollup@2.78.0: + version "2.78.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.78.0.tgz#00995deae70c0f712ea79ad904d5f6b033209d9e" + integrity sha512-4+YfbQC9QEVvKTanHhIAFVUFSRsezvQF8vFOJwtGfb9Bb+r014S+qryr9PSmw8x6sMnPkmFBGAvIFVQxvJxjtg== + optionalDependencies: + fsevents "~2.3.2" + rpc-websockets@^7.5.1: version "7.5.1" resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.5.1.tgz#e0a05d525a97e7efc31a0617f093a13a2e10c401" @@ -7762,6 +8007,13 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +stacktrace-parser@^0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" + integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== + dependencies: + type-fest "^0.7.1" + "statuses@>= 1.5.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -8144,10 +8396,10 @@ tslib@1.14.1, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" - integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, "tslib@^2.4.1 || ^1.9.3": + version "2.6.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" + integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== tsparticles-engine@^2.2.4, tsparticles-engine@^2.9.3: version "2.9.3" @@ -8527,6 +8779,11 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== +type-fest@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" + integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== + typed-array-length@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" @@ -8729,6 +8986,11 @@ webpack-node-externals@3.0.0: resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz#1a3407c158d547a9feb4229a9e3385b7b60c9917" integrity sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ== +"webpack-sources@^2.0.0 || ^3.0.0": + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + webrtc-adapter@^7.2.1: version "7.7.1" resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz#b2c227a6144983b35057df67bd984a7d4bfd17f1"