diff --git a/package.json b/package.json index b89d25bbf3..bb9bfc0cfd 100644 --- a/package.json +++ b/package.json @@ -178,6 +178,7 @@ "@typescript-eslint/eslint-plugin": "^5.58.0", "@typescript-eslint/parser": "^5.58.0", "@vitejs/plugin-react": "^3.1.0", + "@welldone-software/why-did-you-render": "^7.0.1", "babel-plugin-lodash": "^3.3.4", "babel-plugin-macros": "^3.1.0", "env-cmd": "^10.1.0", @@ -207,4 +208,4 @@ "@lingui/core": "3.14.0", "@lingui/conf": "3.16.0" } -} \ No newline at end of file +} diff --git a/src/components/HorizontalScroll.tsx b/src/components/HorizontalScroll.tsx index 25faa23795..839ceb6f77 100644 --- a/src/components/HorizontalScroll.tsx +++ b/src/components/HorizontalScroll.tsx @@ -1,4 +1,4 @@ -import { CSSProperties, ReactNode, useEffect, useRef } from 'react' +import { CSSProperties, Fragment, ReactNode, useEffect, useRef } from 'react' import ScrollContainer from 'react-indiana-drag-scroll' import { Flex } from 'rebass' import styled from 'styled-components' @@ -61,7 +61,9 @@ const HorizontalScroll = ({ > - {(items ?? []).map(renderItem)} + {(items ?? []).map(i => ( + {renderItem(i)} + ))} diff --git a/src/components/YieldPools/ElasticFarmGroup/PostionDetail.tsx b/src/components/YieldPools/ElasticFarmGroup/PostionDetail.tsx index 158b82b7dd..97c4a17256 100644 --- a/src/components/YieldPools/ElasticFarmGroup/PostionDetail.tsx +++ b/src/components/YieldPools/ElasticFarmGroup/PostionDetail.tsx @@ -11,7 +11,7 @@ import PriceVisualize from 'components/ProAmm/PriceVisualize' import { MouseoverTooltipDesktopOnly } from 'components/Tooltip' import useIsTickAtLimit from 'hooks/useIsTickAtLimit' import useTheme from 'hooks/useTheme' -import { useElasticFarms, useFarmAction } from 'state/farms/elastic/hooks' +import { useFarmAction, useUserInfoByFarm } from 'state/farms/elastic/hooks' import { FarmingPool, NFTPosition } from 'state/farms/elastic/types' import { Bound } from 'state/mint/proamm/type' import { formatTickPrice } from 'utils/formatTickPrice' @@ -42,8 +42,8 @@ const PositionDetail = ({ }: Props) => { const theme = useTheme() - const { userFarmInfo } = useElasticFarms() - const joinedPositions = userFarmInfo?.[farmAddress]?.joinedPositions[pool.pid] || [] + const userInfo = useUserInfoByFarm(farmAddress) + const joinedPositions = userInfo?.joinedPositions[pool.pid] || [] const { unstake } = useFarmAction(farmAddress) const joinedInfo = joinedPositions.find(jp => jp.nftId.toString() === item.nftId.toString()) @@ -61,7 +61,7 @@ const PositionDetail = ({ const priceLower = !isRevertPrice ? item.token0PriceLower : item.token0PriceUpper.invert() const priceUpper = !isRevertPrice ? item.token0PriceUpper : item.token0PriceLower.invert() - const rewardByNft = userFarmInfo?.[farmAddress]?.rewardByNft + const rewardByNft = userInfo?.rewardByNft const rewards = rewardByNft?.[pool.pid + '_' + item.nftId.toString()] || [] const rewardValue = rewards.reduce( diff --git a/src/components/YieldPools/ElasticFarmGroup/Row.tsx b/src/components/YieldPools/ElasticFarmGroup/Row.tsx index 9d6e8c9826..832addf5dc 100644 --- a/src/components/YieldPools/ElasticFarmGroup/Row.tsx +++ b/src/components/YieldPools/ElasticFarmGroup/Row.tsx @@ -1,9 +1,8 @@ -import { ChainId, CurrencyAmount, Fraction } from '@kyberswap/ks-sdk-core' -import { computePoolAddress } from '@kyberswap/ks-sdk-elastic' +import { CurrencyAmount, Fraction } from '@kyberswap/ks-sdk-core' import { Trans, t } from '@lingui/macro' import dayjs from 'dayjs' import { BigNumber } from 'ethers' -import { useEffect, useState } from 'react' +import React, { useEffect, useState } from 'react' import { Info, Minus, Plus, Share2 } from 'react-feather' import { Link } from 'react-router-dom' import { useMedia } from 'react-use' @@ -19,15 +18,15 @@ import Harvest from 'components/Icons/Harvest' import InfoHelper from 'components/InfoHelper' import { MouseoverTooltip, MouseoverTooltipDesktopOnly } from 'components/Tooltip' import { APP_PATHS, ELASTIC_BASE_FEE_UNIT } from 'constants/index' -import { NETWORKS_INFO, isEVM } from 'constants/networks' import { TOBE_EXTENDED_FARMING_POOLS } from 'constants/v2' import { useActiveWeb3React } from 'hooks' import { useProMMFarmContract } from 'hooks/useContract' import { useProAmmPositions } from 'hooks/useProAmmPositions' import useTheme from 'hooks/useTheme' import { useShareFarmAddress } from 'state/farms/classic/hooks' -import { useElasticFarms, usePositionFilter } from 'state/farms/elastic/hooks' +import { useDepositedNftsByFarm, usePositionFilter, useUserInfoByFarm } from 'state/farms/elastic/hooks' import { FarmingPool, NFTPosition } from 'state/farms/elastic/types' +import { getPoolAddress } from 'state/mint/proamm/utils' import { useViewMode } from 'state/user/hooks' import { VIEW_MODE } from 'state/user/reducer' import { shortenAddress } from 'utils' @@ -73,26 +72,22 @@ const Row = ({ const above1000 = useMedia('(min-width: 1000px)') const [isRevertPrice, setIsRevertPrice] = useState(false) - const { userFarmInfo } = useElasticFarms() - const joinedPositions = userFarmInfo?.[fairlaunchAddress]?.joinedPositions[farmingPool.pid] || [] + const userInfo = useUserInfoByFarm(fairlaunchAddress) + + const joinedPositions = userInfo?.joinedPositions[farmingPool.pid] || [] + + const depositedPositionsByFarm = useDepositedNftsByFarm(fairlaunchAddress) const depositedPositions = - userFarmInfo?.[fairlaunchAddress]?.depositedPositions.filter(pos => { + depositedPositionsByFarm.filter(pos => { return ( pos.liquidity.toString() !== '0' && - farmingPool.poolAddress.toLowerCase() === - computePoolAddress({ - factoryAddress: NETWORKS_INFO[isEVM(chainId) ? chainId : ChainId.MAINNET].elastic.coreFactory, - tokenA: pos.pool.token0, - tokenB: pos.pool.token1, - fee: pos.pool.fee, - initCodeHashManualOverride: NETWORKS_INFO[isEVM(chainId) ? chainId : ChainId.MAINNET].elastic.initCodeHash, - }).toLowerCase() + farmingPool.poolAddress.toLowerCase() === getPoolAddress(pos.pool).toLowerCase() ) }) || [] const rewardPendings = - userFarmInfo?.[fairlaunchAddress]?.rewardPendings[farmingPool.pid] || + userInfo?.rewardPendings[farmingPool.pid] || farmingPool.rewardTokens.map(token => CurrencyAmount.fromRawAmount(token, 0)) const rewardValue = rewardPendings.reduce( @@ -108,7 +103,7 @@ const Row = ({ useEffect(() => { const getFeeTargetInfo = async () => { if (!contract || farmingPool.feeTarget === '0') return - const userJoinedPos = userFarmInfo?.[fairlaunchAddress].joinedPositions[farmingPool.pid] || [] + const userJoinedPos = userInfo.joinedPositions[farmingPool.pid] || [] if (!userJoinedPos.length) { setTargetPercent('') @@ -143,7 +138,7 @@ const Row = ({ } getFeeTargetInfo() - }, [contract, farmingPool.feeTarget, fairlaunchAddress, farmingPool.pid, userFarmInfo]) + }, [contract, farmingPool.feeTarget, fairlaunchAddress, farmingPool.pid, userInfo]) const { positions } = useProAmmPositions(account) @@ -537,4 +532,4 @@ const Row = ({ ) } -export default Row +export default React.memo(Row) diff --git a/src/components/YieldPools/ElasticFarmGroup/index.tsx b/src/components/YieldPools/ElasticFarmGroup/index.tsx index 83c8d40f1d..6afe935553 100644 --- a/src/components/YieldPools/ElasticFarmGroup/index.tsx +++ b/src/components/YieldPools/ElasticFarmGroup/index.tsx @@ -22,8 +22,8 @@ import { useProAmmNFTPositionManagerContract } from 'hooks/useContract' import useTheme from 'hooks/useTheme' import { Dots } from 'pages/Pool/styleds' import { useWalletModalToggle } from 'state/application/hooks' -import { useElasticFarms, useFarmAction } from 'state/farms/elastic/hooks' -import { FarmingPool, UserInfo } from 'state/farms/elastic/types' +import { useDepositedNftsByFarm, useElasticFarms, useFarmAction, useUserInfoByFarm } from 'state/farms/elastic/hooks' +import { FarmingPool } from 'state/farms/elastic/types' import { useSingleCallResult } from 'state/multicall/hooks' import { useIsTransactionPending } from 'state/transactions/hooks' import { useViewMode } from 'state/user/hooks' @@ -61,7 +61,6 @@ type Props = { pool?: FarmingPool, ) => void pools: FarmingPool[] - userInfo?: UserInfo onShowStepGuide: () => void tokenPrices: { [key: string]: number } } @@ -80,11 +79,14 @@ enum SORT_DIRECTION { DESC = 'desc', } -const ProMMFarmGroup: React.FC = ({ address, onOpenModal, pools, userInfo, onShowStepGuide, tokenPrices }) => { +const ElasticFarmGroup: React.FC = ({ address, onOpenModal, pools, onShowStepGuide, tokenPrices }) => { const theme = useTheme() const { account, chainId } = useActiveWeb3React() const above1000 = useMedia('(min-width: 1000px)') + const depositedPositions = useDepositedNftsByFarm(address) + const userInfo = useUserInfoByFarm(address) + const [searchParams, setSearchParams] = useSearchParams() const sortField = searchParams.get('orderBy') || SORT_FIELD.MY_DEPOSIT const sortDirection = searchParams.get('orderDirection') || SORT_DIRECTION.DESC @@ -92,7 +94,7 @@ const ProMMFarmGroup: React.FC = ({ address, onOpenModal, pools, userInfo const { poolFeeLast24h } = useElasticFarms() const depositedUsd = - userInfo?.depositedPositions.reduce( + depositedPositions.reduce( (acc, cur) => acc + Number(cur.amount0.toExact()) * (tokenPrices[cur.amount0.currency.wrapped.address] || 0) + @@ -101,7 +103,7 @@ const ProMMFarmGroup: React.FC = ({ address, onOpenModal, pools, userInfo ) || 0 const userDepositedTokenAmounts = - userInfo?.depositedPositions.reduce<{ + depositedPositions.reduce<{ [address: string]: CurrencyAmount }>((result, pos) => { const address0 = pos.amount0.currency.address @@ -156,8 +158,8 @@ const ProMMFarmGroup: React.FC = ({ address, onOpenModal, pools, userInfo } const joinedPositions = userInfo?.joinedPositions[pool.pid] || [] - const depositedPositions = - userInfo?.depositedPositions.filter(pos => { + const poolDepositedPositions = + depositedPositions.filter(pos => { return ( pool.poolAddress.toLowerCase() === computePoolAddress({ @@ -171,7 +173,7 @@ const ProMMFarmGroup: React.FC = ({ address, onOpenModal, pools, userInfo ) }) || [] - const depositedUsd = depositedPositions.reduce( + const depositedUsd = poolDepositedPositions.reduce( (usd, pos) => usd + Number(pos.amount1.toExact()) * (tokenPrices[pos.pool.token1.address.toLowerCase()] || 0) + @@ -258,7 +260,7 @@ const ProMMFarmGroup: React.FC = ({ address, onOpenModal, pools, userInfo if (!pools) return null const canHarvest = Object.values(userInfo?.rewardPendings || {}).some(rw => rw.some(item => item.greaterThan('0'))) - const canWithdraw = !!userInfo?.depositedPositions.length + const canWithdraw = !!depositedPositions.length const renderApproveButton = () => { if (isApprovedForAll || tab === 'ended') { @@ -747,4 +749,4 @@ const ProMMFarmGroup: React.FC = ({ address, onOpenModal, pools, userInfo ) } -export default ProMMFarmGroup +export default ElasticFarmGroup diff --git a/src/components/YieldPools/ElasticFarmModals/DepositModal.tsx b/src/components/YieldPools/ElasticFarmModals/DepositModal.tsx index 052d3ebfab..cf18fc4a2a 100644 --- a/src/components/YieldPools/ElasticFarmModals/DepositModal.tsx +++ b/src/components/YieldPools/ElasticFarmModals/DepositModal.tsx @@ -221,7 +221,7 @@ function ProMMDepositNFTModal({ setShowMenu(prev => !prev)}> {filterOptions.find(item => item.code === activeFilter)?.value} - + {showMenu && ( diff --git a/src/components/YieldPools/ElasticFarmModals/styled.tsx b/src/components/YieldPools/ElasticFarmModals/styled.tsx index a57b2c3431..9ea12eca6f 100644 --- a/src/components/YieldPools/ElasticFarmModals/styled.tsx +++ b/src/components/YieldPools/ElasticFarmModals/styled.tsx @@ -88,13 +88,13 @@ export const SelectOption = styled.div` color: ${({ theme }) => theme.subText}; ` -export const DropdownIcon = styled.div<{ rotate?: boolean }>` - transform: rotate(${({ rotate }) => (rotate ? '-180deg' : '0')}); +export const DropdownIcon = styled.div<{ isRotate?: boolean }>` + transform: rotate(${({ isRotate: rotate }) => (rotate ? '-180deg' : '0')}); height: 0; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 4px solid ${({ theme }) => theme.text}; transition: transform 300ms; - transform: rotate(${({ rotate }) => (rotate ? '-180deg' : '0')}); + transform: rotate(${({ isRotate: rotate }) => (rotate ? '-180deg' : '0')}); ` diff --git a/src/components/YieldPools/ElasticFarms.tsx b/src/components/YieldPools/ElasticFarms.tsx index 7b93807166..5ef78a234f 100644 --- a/src/components/YieldPools/ElasticFarms.tsx +++ b/src/components/YieldPools/ElasticFarms.tsx @@ -1,7 +1,6 @@ -import { useRef, useState } from 'react' +import { useState } from 'react' import { Flex } from 'rebass' -import { useOnClickOutside } from 'hooks/useOnClickOutside' import { useFilteredFarms } from 'state/farms/elastic/hooks' import { FarmingPool } from 'state/farms/elastic/types' import { useTokenPrices } from 'state/tokenPrices/hooks' @@ -14,11 +13,7 @@ import WithdrawModal from './ElasticFarmModals/WithdrawModal' type ModalType = 'deposit' | 'withdraw' | 'stake' | 'unstake' | 'harvest' | 'forcedWithdraw' function ElasticFarms({ onShowStepGuide }: { onShowStepGuide: () => void }) { - const ref = useRef() - const [open, setOpen] = useState(false) - useOnClickOutside(ref, open ? () => setOpen(prev => !prev) : undefined) - - const { filteredFarms, farms, userFarmInfo } = useFilteredFarms() + const { filteredFarms, farms } = useFilteredFarms() const [selectedFarm, setSeletedFarm] = useState(null) const [selectedModal, setSeletedModal] = useState(null) @@ -85,7 +80,6 @@ function ElasticFarms({ onShowStepGuide }: { onShowStepGuide: () => void }) { setSeletedPool(pool) }} pools={farm.pools} - userInfo={userFarmInfo?.[farm.id]} tokenPrices={tokenPrices} /> ) diff --git a/src/hooks/useProAmmPositions.ts b/src/hooks/useProAmmPositions.ts index 8054ee1501..8202db984d 100644 --- a/src/hooks/useProAmmPositions.ts +++ b/src/hooks/useProAmmPositions.ts @@ -7,7 +7,7 @@ import { useMemo } from 'react' import { EVMNetworkInfo } from 'constants/networks/type' import { useActiveWeb3React } from 'hooks' -import { useElasticFarms } from 'state/farms/elastic/hooks' +import { useDepositedNfts, useElasticFarms, useJoinedPositions } from 'state/farms/elastic/hooks' import { Result, useSingleCallResult, useSingleContractMultipleData } from 'state/multicall/hooks' import { PositionDetails } from 'types/position' @@ -18,7 +18,7 @@ interface UseProAmmPositionsResults { positions: PositionDetails[] | undefined } -function useProAmmPositionsFromTokenIds(tokenIds: BigNumber[] | undefined): UseProAmmPositionsResults { +export function useProAmmPositionsFromTokenIds(tokenIds: BigNumber[] | undefined): UseProAmmPositionsResults { const positionManager = useProAmmNFTPositionManagerContract() const { isEVM, networkInfo } = useActiveWeb3React() @@ -132,68 +132,64 @@ export function useProAmmPositions(account: string | null | undefined): UseProAm export const useFarmPositions = () => { const { isEVM, networkInfo } = useActiveWeb3React() - const { farms, loading, userFarmInfo, loadingUserInfo } = useElasticFarms() + const { farms, loading } = useElasticFarms() + const userFarmInfo = useJoinedPositions() + const depositedPositions = useDepositedNfts() const farmingPools = useMemo(() => farms?.map(farm => farm.pools).flat() || [], [farms]) - const farmPositions = useMemo(() => { + const farmPositions: PositionDetails[] = useMemo(() => { if (!isEVM) return [] - return Object.values(userFarmInfo || {}) - .map(info => { - return info.depositedPositions - .map(pos => { - const poolAddress = computePoolAddress({ - factoryAddress: (networkInfo as EVMNetworkInfo).elastic.coreFactory, - tokenA: pos.pool.token0, - tokenB: pos.pool.token1, - fee: pos.pool.fee, - initCodeHashManualOverride: (networkInfo as EVMNetworkInfo).elastic.initCodeHash, - }) - const pool = farmingPools.filter(pool => pool.poolAddress.toLowerCase() === poolAddress.toLowerCase()) - - const joinedLiquidity = - // I'm sure we can always find pool - // eslint-disable-next-line - Object.values(info.joinedPositions) - .flat() - .filter(joinedPos => joinedPos.nftId.toString() === pos.nftId.toString()) - .reduce( - (acc, cur) => - acc.gt(BigNumber.from(cur.liquidity.toString())) ? acc : BigNumber.from(cur.liquidity.toString()), - BigNumber.from(0), - ) || BigNumber.from(0) - - return { - nonce: BigNumber.from('1'), - tokenId: pos.nftId, - operator: '0x0000000000000000000000000000000000000000', - poolId: poolAddress, - tickLower: pos.tickLower, - tickUpper: pos.tickUpper, - liquidity: BigNumber.from(pos.liquidity.toString()), - // not used - feeGrowthInsideLast: BigNumber.from(0), - stakedLiquidity: joinedLiquidity, - // not used - rTokenOwed: BigNumber.from(0), - token0: pos.pool.token0.address, - token1: pos.pool.token1.address, - fee: pos.pool.fee, - endTime: pool?.[0]?.endTime, - rewardPendings: [], - } - }) + return Object.values(depositedPositions) + .flat() + .map(pos => { + const poolAddress = computePoolAddress({ + factoryAddress: (networkInfo as EVMNetworkInfo).elastic.coreFactory, + tokenA: pos.pool.token0, + tokenB: pos.pool.token1, + fee: pos.pool.fee, + initCodeHashManualOverride: (networkInfo as EVMNetworkInfo).elastic.initCodeHash, + }) + const pool = farmingPools.filter(pool => pool.poolAddress.toLowerCase() === poolAddress.toLowerCase()) + + const joinedLiquidity = Object.values(userFarmInfo) + .map(item => Object.values(item.joinedPositions).flat()) .flat() + .filter(joinedPos => joinedPos.nftId.toString() === pos.nftId.toString()) + .reduce( + (acc, cur) => + acc.gt(BigNumber.from(cur.liquidity.toString())) ? acc : BigNumber.from(cur.liquidity.toString()), + BigNumber.from(0), + ) + + return { + nonce: BigNumber.from('1'), + tokenId: pos.nftId, + operator: '0x0000000000000000000000000000000000000000', + poolId: poolAddress, + tickLower: pos.tickLower, + tickUpper: pos.tickUpper, + liquidity: BigNumber.from(pos.liquidity.toString()), + // not used + feeGrowthInsideLast: BigNumber.from(0), + stakedLiquidity: joinedLiquidity, + // not used + rTokenOwed: BigNumber.from(0), + token0: pos.pool.token0.address, + token1: pos.pool.token1.address, + fee: pos.pool.fee, + endTime: pool?.[0]?.endTime, + rewardPendings: [], + } }) - .flat() - }, [farmingPools, userFarmInfo, isEVM, networkInfo]) + }, [farmingPools, isEVM, networkInfo, userFarmInfo, depositedPositions]) return useMemo(() => { return { farms, userFarmInfo, farmPositions, - loading: loadingUserInfo || loading, + loading: loading, } - }, [loading, loadingUserInfo, farmPositions, farms, userFarmInfo]) + }, [loading, farmPositions, farms, userFarmInfo]) } diff --git a/src/index.tsx b/src/index.tsx index 5339ccd99e..418efc1a28 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,3 +1,4 @@ +import '@/wdyr' import * as Sentry from '@sentry/react' import { BrowserTracing } from '@sentry/tracing' import { Web3ReactHooks, Web3ReactProvider } from '@web3-react/core' diff --git a/src/pages/Farm/ElasticFarmCombination.tsx b/src/pages/Farm/ElasticFarmCombination.tsx index 695f687ff9..fdec9e1c5b 100644 --- a/src/pages/Farm/ElasticFarmCombination.tsx +++ b/src/pages/Farm/ElasticFarmCombination.tsx @@ -1,5 +1,5 @@ import { Trans } from '@lingui/macro' -import { FC, useEffect, useMemo, useState } from 'react' +import { FC, Fragment, useCallback, useEffect, useMemo, useState } from 'react' import { useSearchParams } from 'react-router-dom' import { useMedia } from 'react-use' import { Flex, Text } from 'rebass' @@ -70,6 +70,9 @@ export const ElasticFarmCombination: FC = () => { const upToExtraSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToExtraSmall}px)`) + const showFarmV2 = useCallback(() => setShowFarmStepGuide('v2'), []) + const showFarmV1 = useCallback(() => setShowFarmStepGuide('v1'), []) + if (loading && noFarms) { return ( { overflow: upToExtraSmall ? undefined : 'hidden', }} > - setShowFarmStepGuide('v1')} /> + {!!filteredFarmsV1.length && !!filteredFarmsV2.length && } {Object.keys(farmByContract).map((contract, index) => ( - <> - setShowFarmStepGuide('v2')} farmAddress={contract} key={contract} /> + + {index !== Object.keys(farmByContract).length - 1 && } - + ))} diff --git a/src/state/farms/elastic/hooks.ts b/src/state/farms/elastic/hooks.ts index 62303b369c..9d2b137203 100644 --- a/src/state/farms/elastic/hooks.ts +++ b/src/state/farms/elastic/hooks.ts @@ -3,9 +3,11 @@ import { Currency, CurrencyAmount, Token } from '@kyberswap/ks-sdk-core' import { FeeAmount, Position, computePoolAddress } from '@kyberswap/ks-sdk-elastic' import { t } from '@lingui/macro' import { BigNumber } from 'ethers' +import { Interface } from 'ethers/lib/utils' import { useCallback, useMemo, useState } from 'react' import { useSearchParams } from 'react-router-dom' +import ELASTIC_FARM_ABI from 'constants/abis/v2/farm.json' import { ELASTIC_FARM_TYPE, FARM_TAB } from 'constants/index' import { CONTRACT_NOT_FOUND_MSG } from 'constants/messages' import { isEVM as isEVMNetwork } from 'constants/networks' @@ -14,8 +16,11 @@ import { useActiveWeb3React } from 'hooks' import { useTokens } from 'hooks/Tokens' import { useProAmmNFTPositionManagerContract, useProMMFarmContract } from 'hooks/useContract' import { usePools } from 'hooks/usePools' -import { FarmingPool, NFTPosition } from 'state/farms/elastic/types' +import { useProAmmPositionsFromTokenIds } from 'hooks/useProAmmPositions' +import { FarmingPool, NFTPosition, UserFarmInfo, UserInfo } from 'state/farms/elastic/types' import { useAppSelector } from 'state/hooks' +import { getPoolAddress } from 'state/mint/proamm/utils' +import { toCallState, useCallsData, useMultipleContractSingleData } from 'state/multicall/hooks' import { useTransactionAdder } from 'state/transactions/hooks' import { TRANSACTION_TYPE, @@ -38,12 +43,13 @@ export const useElasticFarms = () => { export const useFilteredFarms = () => { const { isEVM, networkInfo, chainId } = useActiveWeb3React() + const depositedPositions = useDepositedNfts() const [searchParams] = useSearchParams() const filteredToken0Id = searchParams.get('token0') || undefined const filteredToken1Id = searchParams.get('token1') || undefined - const { farms, loading, userFarmInfo } = useElasticFarms() + const { farms, loading } = useElasticFarms() const type = searchParams.get('type') const activeTab: string = type || FARM_TAB.ACTIVE @@ -130,10 +136,10 @@ export const useFilteredFarms = () => { if (activeTab === FARM_TAB.MY_FARMS && isEVM) { result = result?.map(item => { - if (!userFarmInfo?.[item.id].depositedPositions.length) { + if (!depositedPositions[item.id]?.length) { return { ...item, pools: [] } } - const stakedPools = userFarmInfo?.[item.id].depositedPositions.map(pos => + const stakedPools = depositedPositions[item.id]?.map(pos => computePoolAddress({ factoryAddress: (networkInfo as EVMNetworkInfo).elastic.coreFactory, tokenA: pos.pool.token0, @@ -154,7 +160,7 @@ export const useFilteredFarms = () => { search, activeTab, chainId, - userFarmInfo, + depositedPositions, isEVM, networkInfo, filteredToken0Id, @@ -165,7 +171,6 @@ export const useFilteredFarms = () => { return { farms, loading, - userFarmInfo, filteredFarms, } } @@ -498,3 +503,176 @@ export const usePositionFilter = (positions: PositionDetails[], validPools: stri filterOptions, } } + +const farmInterface = new Interface(ELASTIC_FARM_ABI) + +export function useDepositedNfts(): { [address: string]: NFTPosition[] } { + const { farms } = useElasticFarms() + const farmAddresses = useMemo(() => { + return farms?.map(item => item.id) || [] + }, [farms]) + + const { account } = useActiveWeb3React() + + const inputs = useMemo(() => [account], [account]) + const options = useMemo( + () => ({ + blocksPerFetch: 40, + }), + [], + ) + const result = useMultipleContractSingleData(farmAddresses, farmInterface, 'getDepositedNFTs', inputs, options) + + const nftByFarmAddress = useMemo(() => { + const res: { [key: string]: BigNumber[] } = {} + result.forEach((item, idx) => { + res[farmAddresses[idx]] = item.result?.listNFTs || [] + }) + return res + }, [result, farmAddresses]) + + const tokenIds = useMemo(() => { + return Object.values(nftByFarmAddress).flat() + }, [nftByFarmAddress]) + const { positions = [] } = useProAmmPositionsFromTokenIds(tokenIds) + + return useMemo(() => { + const positionByFarmAddess: { [key: string]: Array } = {} + + farmAddresses.forEach(address => { + const { pools } = farms?.find(item => item.id === address) || {} + + positionByFarmAddess[address] = (nftByFarmAddress[address] || []) + .map((id: BigNumber) => { + const position = positions.find(item => item.tokenId.toString() === id.toString()) + const pool = pools?.find(pool => pool.poolAddress.toLowerCase() === position?.poolId.toLowerCase())?.pool + if (!pool || !position) return null + return new NFTPosition({ + nftId: id, + pool, + liquidity: position.liquidity.toString(), + tickLower: position.tickLower, + tickUpper: position.tickUpper, + }) + }) + .filter(item => item !== null) as NFTPosition[] + }) + + return positionByFarmAddess + }, [farms, positions, nftByFarmAddress, farmAddresses]) +} + +export function useDepositedNftsByFarm(farmAddress: string): NFTPosition[] { + const positionByFarm = useDepositedNfts() + return useMemo(() => positionByFarm[farmAddress] || [], [positionByFarm, farmAddress]) +} + +const getUserInfoFragment = farmInterface.getFunction('getUserInfo') + +export function useJoinedPositions() { + const positions = useDepositedNfts() + const { farms } = useElasticFarms() + + const params = useMemo(() => { + return (farms || []).map(farm => { + const calls: { address: string; callData: string; pos: NFTPosition; pid: string }[] = [] + + const deposited = positions[farm.id] || [] + deposited.forEach(pos => { + const poolAddress = getPoolAddress(pos.pool) + const matchedPools = farm.pools.filter(p => p.poolAddress.toLowerCase() === poolAddress.toLowerCase()) + + matchedPools.forEach(pool => { + if (pos.liquidity.toString() !== '0') + calls.push({ + address: farm.id, + callData: farmInterface.encodeFunctionData(getUserInfoFragment, [pos.nftId, pool.pid]), + pid: pool.pid.toString(), + pos: pos, + }) + }) + }) + return calls + }) + }, [farms, positions]) + + const options = useMemo( + () => ({ + blocksPerFetch: 30, + }), + [], + ) + const callInputs = useMemo(() => params.flat(), [params]) + const rawRes = useCallsData(callInputs, options) + + const result = useMemo(() => rawRes.map(item => toCallState(item, farmInterface, getUserInfoFragment)), [rawRes]) + + return useMemo(() => { + const userInfo: UserFarmInfo = {} + farms?.forEach((farm, idx) => { + const joinedPositions: { [pid: string]: NFTPosition[] } = {} + const rewardPendings: { [pid: string]: CurrencyAmount[] } = {} + const rewardByNft: { [pid_nftId: string]: CurrencyAmount[] } = {} + + const startIdx = idx === 0 ? 0 : params.slice(0, idx + 1).reduce((acc, cur) => acc + cur.length, 0) + const endIdx = startIdx + params[idx].length + + const res = result.slice(startIdx, endIdx) + + params[idx].forEach((param, index) => { + const pid = param.pid.toString() + const nftId = param.pos.nftId + + if (res[index].result) { + if (!joinedPositions[pid]) { + joinedPositions[pid] = [] + } + + const depositedPos = positions[farm.id].find(pos => pos.nftId.eq(nftId)) + const farmingPool = farm.pools.find(p => p.pid === pid) + + if (depositedPos && farmingPool) { + const pos = new NFTPosition({ + nftId, + liquidity: res[index].result?.liquidity, + tickLower: depositedPos.tickLower, + tickUpper: depositedPos.tickUpper, + pool: depositedPos.pool, + }) + joinedPositions[pid].push(pos) + + const id = `${pid}_${nftId.toString()}` + if (!rewardByNft[id]) { + rewardByNft[id] = [] + } + if (!rewardPendings[pid]) { + rewardPendings[pid] = [] + } + farmingPool.rewardTokens.forEach((currency, i) => { + const amount = CurrencyAmount.fromRawAmount(currency, res[index].result?.rewardPending[i]) + rewardByNft[id][i] = amount + + if (!rewardPendings[pid][i]) { + rewardPendings[pid][i] = amount + } else { + rewardPendings[pid][i] = rewardPendings[pid][i].add(amount) + } + }) + } + } + }) + + userInfo[farm.id] = { + joinedPositions, + rewardPendings, + rewardByNft, + } + }) + return userInfo + }, [result, params, farms, positions]) +} + +export function useUserInfoByFarm(farmAddress: string): UserInfo { + const userFarmsInfo = useJoinedPositions() + return useMemo(() => userFarmsInfo[farmAddress] || {}, [userFarmsInfo, farmAddress]) +} diff --git a/src/state/farms/elastic/index.ts b/src/state/farms/elastic/index.ts index 0662cd98e5..9788ef976f 100644 --- a/src/state/farms/elastic/index.ts +++ b/src/state/farms/elastic/index.ts @@ -1,13 +1,11 @@ import { createSlice } from '@reduxjs/toolkit' -import { ElasticFarm, UserFarmInfo } from './types' +import { ElasticFarm } from './types' interface ElasticFarmState { [chainId: number]: { loading: boolean farms: ElasticFarm[] | null - userFarmInfo?: UserFarmInfo - loadingUserInfo: boolean poolFeeLast24h: { [poolId: string]: number } @@ -18,7 +16,6 @@ export const defaultChainData = { loading: false, farms: [], poolFeeLast24h: {}, - loadingUserInfo: false, } as ElasticFarmState[number] const initialState: ElasticFarmState = {} @@ -38,25 +35,12 @@ const slice = createSlice({ } else state[chainId] = { ...state[chainId], loading } }, - setUserFarmInfo( - state, - { payload: { userInfo, chainId } }: { payload: { userInfo: UserFarmInfo; chainId: number } }, - ) { - state[chainId].userFarmInfo = userInfo - }, - setPoolFeeData(state, { payload: { chainId, data } }) { state[chainId].poolFeeLast24h = data }, - - setLoadingUserInfo(state, { payload: { loading, chainId } }) { - if (!state[chainId]) { - state[chainId] = { ...defaultChainData, loadingUserInfo: loading } - } else state[chainId] = { ...state[chainId], loadingUserInfo: loading } - }, }, }) -export const { setFarms, setLoading, setUserFarmInfo, setPoolFeeData, setLoadingUserInfo } = slice.actions +export const { setFarms, setLoading, setPoolFeeData } = slice.actions export default slice.reducer diff --git a/src/state/farms/elastic/types.ts b/src/state/farms/elastic/types.ts index e3c9f0c60a..cdeff655aa 100644 --- a/src/state/farms/elastic/types.ts +++ b/src/state/farms/elastic/types.ts @@ -50,7 +50,6 @@ export class NFTPosition extends Position { } export interface UserInfo { - depositedPositions: NFTPosition[] joinedPositions: { [pid: string]: NFTPosition[] } diff --git a/src/state/farms/elastic/updaters/index.tsx b/src/state/farms/elastic/updaters/index.tsx index 426e4dda50..7dc46ae736 100644 --- a/src/state/farms/elastic/updaters/index.tsx +++ b/src/state/farms/elastic/updaters/index.tsx @@ -11,7 +11,7 @@ export type CommonProps = { const FarmUpdater: React.FC = ({ interval = true }) => { const { isEnableKNProtocol } = useKyberSwapConfig() - useGetUserFarmingInfo(interval) + useGetUserFarmingInfo() if (isEnableKNProtocol) { return diff --git a/src/state/farms/elastic/updaters/useGetUserElasticFarmInfo.ts b/src/state/farms/elastic/updaters/useGetUserElasticFarmInfo.ts index 40ae345941..e7937aa06d 100644 --- a/src/state/farms/elastic/updaters/useGetUserElasticFarmInfo.ts +++ b/src/state/farms/elastic/updaters/useGetUserElasticFarmInfo.ts @@ -1,27 +1,14 @@ import { gql, useLazyQuery } from '@apollo/client' -import { defaultAbiCoder } from '@ethersproject/abi' -import { getCreate2Address } from '@ethersproject/address' -import { keccak256 } from '@ethersproject/solidity' -import { Currency, CurrencyAmount } from '@kyberswap/ks-sdk-core' -import { BigNumber } from 'ethers' -import { Interface } from 'ethers/lib/utils' -import { useCallback, useEffect, useRef } from 'react' +import { useEffect } from 'react' import { useDispatch } from 'react-redux' -import NFTPositionManagerABI from 'constants/abis/v2/ProAmmNFTPositionManager.json' -import ELASTIC_FARM_ABI from 'constants/abis/v2/farm.json' -import { NETWORKS_INFO, isEVM } from 'constants/networks' +import { isEVM } from 'constants/networks' import { useActiveWeb3React } from 'hooks' -import { useMulticallContract } from 'hooks/useContract' import { useKyberSwapConfig } from 'state/application/hooks' import { useAppSelector } from 'state/hooks' import { usePoolBlocks } from 'state/prommPools/hooks' -import { setLoadingUserInfo, setPoolFeeData, setUserFarmInfo } from '..' -import { NFTPosition, UserFarmInfo } from '../types' - -const farmInterface = new Interface(ELASTIC_FARM_ABI) -const positionManagerInterface = new Interface(NFTPositionManagerABI.abi) +import { setPoolFeeData } from '..' const POOL_FEE_HISTORY = gql` query poolFees($block: Int!, $poolIds: [String]!) { @@ -32,225 +19,12 @@ const POOL_FEE_HISTORY = gql` } ` -const defaultChainData = { - loading: false, - farms: null, - poolFeeLast24h: {}, -} -const useGetUserFarmingInfo = (interval?: boolean) => { +const useGetUserFarmingInfo = () => { const dispatch = useDispatch() - const { chainId, account } = useActiveWeb3React() - const multicallContract = useMulticallContract() + const { chainId } = useActiveWeb3React() const { elasticClient } = useKyberSwapConfig() - const elasticFarm = useAppSelector(state => state.elasticFarm[chainId || 1]) || defaultChainData - - const getUserFarmInfo = useCallback(async () => { - const farmAddresses = elasticFarm.farms?.map(farm => farm.id) - - if (isEVM(chainId) && account && farmAddresses?.length && multicallContract) { - dispatch(setLoadingUserInfo({ loading: true, chainId })) - // get userDepositedNFTs - const userDepositedNFTsFragment = farmInterface.getFunction('getDepositedNFTs') - const callData = farmInterface.encodeFunctionData(userDepositedNFTsFragment, [account]) - - const chunks = farmAddresses.map(address => ({ - target: address, - callData, - })) - - const multicallRes = await multicallContract.callStatic.tryBlockAndAggregate(false, chunks) - const returnData = multicallRes.returnData - // listNFTs by contract - const nftResults: Array> = returnData.map((data: [boolean, string]) => { - try { - return data[0] ? farmInterface.decodeFunctionResult(userDepositedNFTsFragment, data[1]).listNFTs : [] - } catch { - return [] - } - }) - - /* - * GET DETAIL NFT - */ - const allNFTs = nftResults.flat() - const nftDetailFragment = positionManagerInterface.getFunction('positions') - const nftDetailChunks = allNFTs.map(id => ({ - target: NETWORKS_INFO[chainId].elastic.nonfungiblePositionManager, - callData: positionManagerInterface.encodeFunctionData(nftDetailFragment, [id]), - })) - - const detailNFTMultiCallData = (await multicallContract.callStatic.tryBlockAndAggregate(false, nftDetailChunks)) - .returnData - - const nftDetailResult = detailNFTMultiCallData.map((data: [boolean, string]) => - data[0] ? positionManagerInterface.decodeFunctionResult(nftDetailFragment, data[1]) : null, - ) - - type NFT_INFO = { - [id: string]: { - poolAddress: string - liquidity: BigNumber - tickLower: BigNumber - tickUpper: BigNumber - } - } - const nftInfos = nftDetailResult.reduce((acc: NFT_INFO, item: any, index: number) => { - if (!item) return acc - return { - ...acc, - [allNFTs[index].toString()]: { - poolAddress: getCreate2Address( - NETWORKS_INFO[chainId].elastic.coreFactory, - keccak256( - ['bytes'], - [ - defaultAbiCoder.encode( - ['address', 'address', 'uint24'], - [item.info.token0, item.info.token1, item.info.fee], - ), - ], - ), - NETWORKS_INFO[chainId].elastic.initCodeHash, - ), - liquidity: item.pos.liquidity, - tickLower: item.pos.tickLower, - tickUpper: item.pos.tickUpper, - }, - } - }, {} as NFT_INFO) - - const promises = - elasticFarm.farms?.map(async (farm, index) => { - const nfts = nftResults[index] - - const depositedPositions: NFTPosition[] = [] - const joinedPositions: { [pid: string]: NFTPosition[] } = {} - const rewardPendings: { [pid: string]: CurrencyAmount[] } = {} - const rewardByNft: { [pid_nftId: string]: CurrencyAmount[] } = {} - - const userInfoParams: Array<[BigNumber, string]> = [] - nfts.forEach(id => { - const matchedPools = farm.pools.filter( - p => p.poolAddress.toLowerCase() === nftInfos[id.toString()]?.poolAddress.toLowerCase(), - ) - - matchedPools.forEach(pool => { - userInfoParams.push([id, pool.pid]) - }) - - if (matchedPools?.[0]) { - const pos = new NFTPosition({ - nftId: id, - pool: matchedPools[0].pool, - liquidity: nftInfos[id.toString()].liquidity, - tickLower: nftInfos[id.toString()].tickLower, - tickUpper: nftInfos[id.toString()].tickUpper, - }) - depositedPositions.push(pos) - } - }) - - const getUserInfoFragment = farmInterface.getFunction('getUserInfo') - if (nfts.length) { - const returnData = ( - await multicallContract.callStatic.tryBlockAndAggregate( - false, - userInfoParams.map(params => { - return { - target: farm.id, - callData: farmInterface.encodeFunctionData(getUserInfoFragment, params), - } - }), - ) - ).returnData.map((item: [boolean, string]) => item[1]) - - const result = returnData.map((data: string) => { - try { - return farmInterface.decodeFunctionResult(getUserInfoFragment, data) - } catch (e) { - return e - } - }) - userInfoParams.forEach((param, index) => { - const pid = param[1].toString() - const nftId = param[0] - if (!(result[index] instanceof Error)) { - if (!joinedPositions[pid]) { - joinedPositions[pid] = [] - } - - const depositedPos = depositedPositions.find(pos => pos.nftId.eq(nftId)) - const farmingPool = farm.pools.find(p => p.pid === pid) - - if (depositedPos && farmingPool) { - const pos = new NFTPosition({ - nftId, - liquidity: result[index].liquidity, - tickLower: depositedPos.tickLower, - tickUpper: depositedPos.tickUpper, - pool: depositedPos.pool, - }) - joinedPositions[pid].push(pos) - - const id = `${pid}_${nftId.toString()}` - if (!rewardByNft[id]) { - rewardByNft[id] = [] - } - if (!rewardPendings[pid]) { - rewardPendings[pid] = [] - } - farmingPool.rewardTokens.forEach((currency, i) => { - const amount = CurrencyAmount.fromRawAmount(currency, result[index].rewardPending[i]) - rewardByNft[id][i] = amount - - if (!rewardPendings[pid][i]) { - rewardPendings[pid][i] = amount - } else { - rewardPendings[pid][i] = rewardPendings[pid][i].add(amount) - } - }) - } - } - }) - } - return { - depositedPositions, - joinedPositions, - rewardPendings, - rewardByNft, - } - }) || [] - - const res = await Promise.all(promises) - - const userInfo = elasticFarm.farms?.reduce((userInfo, farm, index) => { - return { - ...userInfo, - [farm.id]: res[index], - } - }, {} as UserFarmInfo) - - dispatch(setLoadingUserInfo({ chainId, loading: false })) - if (userInfo) dispatch(setUserFarmInfo({ chainId, userInfo })) - } - }, [elasticFarm.farms, chainId, account, multicallContract, dispatch]) - - const getUserFarmInfoRef = useRef(getUserFarmInfo) - getUserFarmInfoRef.current = getUserFarmInfo - - useEffect(() => { - getUserFarmInfoRef.current() - - const i = interval - ? setInterval(() => { - getUserFarmInfoRef.current() - }, 10_000) - : undefined - return () => { - i && clearInterval(i) - } - }, [interval, account, elasticFarm.farms?.length]) + const farms = useAppSelector(state => state.elasticFarm[chainId || 1]?.farms) const { blockLast24h } = usePoolBlocks() const [getPoolInfo, { data: poolFeeData }] = useLazyQuery(POOL_FEE_HISTORY, { @@ -276,7 +50,7 @@ const useGetUserFarmingInfo = (interval?: boolean) => { useEffect(() => { if (!isEVM(chainId)) return - const poolIds = elasticFarm.farms?.map(item => item.pools.map(p => p.poolAddress.toLowerCase())).flat() + const poolIds = farms?.map(item => item.pools.map(p => p.poolAddress.toLowerCase())).flat() if (blockLast24h && poolIds?.length) { getPoolInfo({ @@ -286,7 +60,7 @@ const useGetUserFarmingInfo = (interval?: boolean) => { }, }) } - }, [elasticFarm.farms, blockLast24h, getPoolInfo, chainId]) + }, [farms, blockLast24h, getPoolInfo, chainId]) } export default useGetUserFarmingInfo diff --git a/src/state/farms/elastic/updaters/v1.tsx b/src/state/farms/elastic/updaters/v1.tsx index 028ac26b2f..6d1958b937 100644 --- a/src/state/farms/elastic/updaters/v1.tsx +++ b/src/state/farms/elastic/updaters/v1.tsx @@ -1,5 +1,5 @@ import { gql, useLazyQuery } from '@apollo/client' -import { ChainId, CurrencyAmount, Token, TokenAmount, WETH } from '@kyberswap/ks-sdk-core' +import { CurrencyAmount, Token, TokenAmount, WETH } from '@kyberswap/ks-sdk-core' import { FeeAmount, Pool, Position } from '@kyberswap/ks-sdk-elastic' import { useEffect } from 'react' @@ -153,9 +153,11 @@ const FarmUpdaterV1: React.FC = ({ interval }) => { useEffect(() => { if (!elasticFarm.farms && !elasticFarm.loading) { dispatch(setLoading({ chainId, loading: true })) - getElasticFarms().finally(() => { + try { + getElasticFarms() + } finally { dispatch(setLoading({ chainId, loading: false })) - }) + } } }, [elasticFarm, getElasticFarms, dispatch, chainId]) @@ -163,7 +165,7 @@ const FarmUpdaterV1: React.FC = ({ interval }) => { const i = interval ? setInterval(() => { getElasticFarms() - }, 10_000) + }, 20_000) : undefined return () => { i && clearInterval(i) @@ -178,7 +180,7 @@ const FarmUpdaterV1: React.FC = ({ interval }) => { }, [error, dispatch, chainId]) useEffect(() => { - if (data?.farms && chainId) { + if (data?.farms && chainId && !elasticFarm?.farms?.length) { // transform farm data const formattedData: ElasticFarm[] = data.farms.map((farm: SubgraphFarm) => { return { @@ -236,7 +238,7 @@ const FarmUpdaterV1: React.FC = ({ interval }) => { return { startTime: Number(pool.startTime), - endTime: chainId === ChainId.AVAXMAINNET && pool.pid === '125' ? 1680104783 : Number(pool.endTime), + endTime: Number(pool.endTime), pid: pool.pid, id: pool.id, feeTarget: pool.feeTarget, @@ -266,7 +268,7 @@ const FarmUpdaterV1: React.FC = ({ interval }) => { }) dispatch(setFarms({ chainId, farms: formattedData })) } - }, [data, dispatch, chainId]) + }, [data, dispatch, chainId, elasticFarm]) return null } diff --git a/src/state/farms/elastic/updaters/v2.tsx b/src/state/farms/elastic/updaters/v2.tsx index 88c31bd99f..0494a5e3c5 100644 --- a/src/state/farms/elastic/updaters/v2.tsx +++ b/src/state/farms/elastic/updaters/v2.tsx @@ -48,7 +48,9 @@ const useGetElasticFarms = () => { : '' return useSWR(endpoint, (url: string) => fetch(url).then(resp => resp.json()), { - refreshInterval: 10_000, + revalidateIfStale: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, }) } diff --git a/src/state/farms/elasticv2/updater.tsx b/src/state/farms/elasticv2/updater.tsx index 3327c123b2..ef521f06dd 100644 --- a/src/state/farms/elasticv2/updater.tsx +++ b/src/state/farms/elasticv2/updater.tsx @@ -173,6 +173,9 @@ export default function ElasticFarmV2Updater({ interval = true }: { interval?: b const { fetchPrices } = useTokenPricesWithLoading([]) + const tokensRef = useRef([]) + const pricesRef = useRef<{ [key: string]: number | undefined }>({}) + useEffect(() => { const getData = async () => { if (data?.farmV2S.length && chainId) { @@ -192,7 +195,12 @@ export default function ElasticFarmV2Updater({ interval = true }: { interval?: b ), ] as string[] - const prices = await fetchPrices(tokens) + let prices = pricesRef.current + if (tokensRef.current.sort().join() !== tokens.sort().join()) { + tokensRef.current = tokens + prices = await fetchPrices(tokens) + pricesRef.current = prices + } const formattedData: ElasticFarmV2[] = data.farmV2S.map((farm: SubgraphFarmV2) => { const getToken = (t: SubgraphToken, keepWrapped = false) => { diff --git a/src/state/mint/proamm/utils.ts b/src/state/mint/proamm/utils.ts index a69b7d9eaf..d8efdc6afa 100644 --- a/src/state/mint/proamm/utils.ts +++ b/src/state/mint/proamm/utils.ts @@ -1,14 +1,20 @@ +import { defaultAbiCoder } from '@ethersproject/abi' +import { keccak256 } from '@ethersproject/solidity' import { Price, Token } from '@kyberswap/ks-sdk-core' import { FeeAmount, + Pool, TICK_SPACINGS, TickMath, encodeSqrtRatioX96, nearestUsableTick, priceToClosestTick, } from '@kyberswap/ks-sdk-elastic' +import { getCreate2Address } from 'ethers/lib/utils' import JSBI from 'jsbi' +import { NETWORKS_INFO } from 'constants/networks' +import { EVMNetworkInfo } from 'constants/networks/type' import { rangeData } from 'pages/AddLiquidityV2/constants' import { PairFactor } from 'state/topTokens/type' @@ -88,3 +94,15 @@ export const getRangeTicks = ( return result } + +export function getPoolAddress(pool: Pool): string { + const networkInfo = NETWORKS_INFO[pool.token0.chainId] as EVMNetworkInfo + return getCreate2Address( + networkInfo.elastic.coreFactory, + keccak256( + ['bytes'], + [defaultAbiCoder.encode(['address', 'address', 'uint24'], [pool.token0.address, pool.token1.address, pool.fee])], + ), + networkInfo.elastic.initCodeHash, + ) +} diff --git a/src/state/multicall/hooks.ts b/src/state/multicall/hooks.ts index 3b5a4b09c2..8460ae845b 100644 --- a/src/state/multicall/hooks.ts +++ b/src/state/multicall/hooks.ts @@ -2,12 +2,11 @@ import { FunctionFragment, Interface } from '@ethersproject/abi' import { BigNumber } from '@ethersproject/bignumber' import { Contract } from '@ethersproject/contracts' import { ChainId } from '@kyberswap/ks-sdk-core' -import { useEffect, useMemo } from 'react' +import { useEffect, useMemo, useRef } from 'react' import { useDispatch, useSelector } from 'react-redux' import { EMPTY_ARRAY } from 'constants/index' import { useActiveWeb3React } from 'hooks' -import { useBlockNumber } from 'state/application/hooks' import { AppDispatch, AppState } from 'state/index' import { @@ -53,7 +52,7 @@ export const NEVER_RELOAD: ListenerOptions = { } // the lowest level call for subscribing to contract data -function useCallsData(calls: (Call | undefined)[], options?: ListenerOptions): CallResult[] { +export function useCallsData(calls: (Call | undefined)[], options?: ListenerOptions): CallResult[] { const { chainId, isEVM } = useActiveWeb3React() const callResults = useSelector( state => state.multicall.callResults?.[chainId], @@ -98,23 +97,40 @@ function useCallsData(calls: (Call | undefined)[], options?: ListenerOptions): C } }, [isEVM, dispatch, options, serializedCallKeys, chainId]) - return useMemo( - () => - isEVM && calls.length - ? calls.map(call => { - if (!call) return INVALID_RESULT - - const result = callResults?.[toCallKey(call)] - let data - if (result?.data && result?.data !== '0x') { - data = result.data - } + const lastResults = useRef([]) + return useMemo(() => { + let isChanged = lastResults.current.length !== calls.length + + // Construct results using a for-loop to handle sparse arrays. + // Array.prototype.map would skip empty entries. + const results: CallResult[] = [] + for (let i = 0; i < calls.length; ++i) { + const call = calls[i] + let result = INVALID_RESULT + if (call) { + const callResult = callResults?.[toCallKey(call)] + result = { + valid: true, + data: callResult?.data && callResult.data !== '0x' ? callResult.data : undefined, + blockNumber: callResult?.blockNumber, + } + } - return { valid: true, data, blockNumber: result?.blockNumber } - }) - : EMPTY_ARRAY, - [callResults, calls, isEVM], - ) + isChanged = isChanged || !areCallResultsEqual(result, lastResults.current[i]) + results.push(result) + } + + // Force the results to be referentially stable if they have not changed. + // This is necessary because *all* callResults are passed as deps when initially memoizing the results. + if (isChanged) { + lastResults.current = results + } + return lastResults.current + }, [callResults, calls]) +} + +function areCallResultsEqual(a: CallResult, b: CallResult) { + return a.valid === b.valid && a.data === b.data && a.blockNumber === b.blockNumber } interface CallState { @@ -124,27 +140,24 @@ interface CallState { // true if the result has never been fetched readonly loading: boolean // true if the result is not for the latest block - readonly syncing: boolean + // readonly syncing: boolean // true if the call was made and is synced, but the return data is invalid readonly error: boolean } -const INVALID_CALL_STATE: CallState = { valid: false, result: undefined, loading: false, syncing: false, error: false } -const LOADING_CALL_STATE: CallState = { valid: true, result: undefined, loading: true, syncing: true, error: false } +const INVALID_CALL_STATE: CallState = { valid: false, result: undefined, loading: false, error: false } +const LOADING_CALL_STATE: CallState = { valid: true, result: undefined, loading: true, error: false } -function toCallState( +export function toCallState( callResult: CallResult | undefined, contractInterface: Interface | undefined, fragment: FunctionFragment | undefined, - latestBlockNumber: number | undefined, ): CallState { - if (!callResult) return INVALID_CALL_STATE - const { valid, data, blockNumber } = callResult - if (!valid) return INVALID_CALL_STATE - if (valid && !blockNumber) return LOADING_CALL_STATE - if (!contractInterface || !fragment || !latestBlockNumber) return LOADING_CALL_STATE + if (!callResult || !callResult.valid) return INVALID_CALL_STATE + const { data, blockNumber } = callResult + if (!blockNumber || !contractInterface || !fragment) return LOADING_CALL_STATE const success = data && data.length > 2 - const syncing = (blockNumber ?? 0) < latestBlockNumber + // const syncing = blockNumber < latestBlockNumber let result: Result | undefined = undefined if (success && data) { try { @@ -155,7 +168,6 @@ function toCallState( valid: true, loading: false, error: true, - syncing, result, } } @@ -163,7 +175,6 @@ function toCallState( return { valid: true, loading: false, - syncing, result: result, error: !success, } @@ -197,11 +208,9 @@ export function useSingleContractMultipleData( const results = useCallsData(calls, options) - const latestBlockNumber = useBlockNumber() - return useMemo(() => { - return isEVM ? results.map(result => toCallState(result, contract?.interface, fragment, latestBlockNumber)) : [] - }, [isEVM, fragment, contract, results, latestBlockNumber]) + return isEVM ? results.map(result => toCallState(result, contract?.interface, fragment)) : [] + }, [isEVM, fragment, contract, results]) } export function useMultipleContractSingleData( @@ -243,12 +252,10 @@ export function useMultipleContractSingleData( const results = useCallsData(calls, options) - const latestBlockNumber = useBlockNumber() - return useMemo(() => { - if (isEVM) return results.map(result => toCallState(result, contractInterface, fragment, latestBlockNumber)) + if (isEVM) return results.map(result => toCallState(result, contractInterface, fragment)) return [] - }, [isEVM, results, contractInterface, fragment, latestBlockNumber]) + }, [isEVM, results, contractInterface, fragment]) } export function useSingleCallResult( @@ -276,11 +283,10 @@ export function useSingleCallResult( }, [isEVM, contract, fragment, inputs, gasRequired]) const { valid, data, blockNumber } = useCallsData(calls, options)[0] || {} - const latestBlockNumber = useBlockNumber() return useMemo(() => { - return toCallState({ valid, data, blockNumber }, contract?.interface, fragment, latestBlockNumber) - }, [valid, data, blockNumber, contract, fragment, latestBlockNumber]) + return toCallState({ valid, data, blockNumber }, contract?.interface, fragment) + }, [valid, data, blockNumber, contract, fragment]) } export function useSingleContractWithCallData( @@ -305,16 +311,9 @@ export function useSingleContractWithCallData( const results = useCallsData(calls, options) - const latestBlockNumber = useBlockNumber() - return useMemo(() => { return results.map((result, i) => - toCallState( - result, - contract?.interface, - contract?.interface?.getFunction(callDatas[i].substring(0, 10)), - latestBlockNumber, - ), + toCallState(result, contract?.interface, contract?.interface?.getFunction(callDatas[i].substring(0, 10))), ) - }, [contract, results, latestBlockNumber, callDatas]) + }, [contract, results, callDatas]) } diff --git a/src/wdyr.ts b/src/wdyr.ts new file mode 100644 index 0000000000..fb011c3ed6 --- /dev/null +++ b/src/wdyr.ts @@ -0,0 +1,14 @@ +// eslint-disable-next-line +/// +import whyDidYouRender from '@welldone-software/why-did-you-render' +import * as React from 'react' +import * as ReactRedux from 'react-redux' + +if (import.meta.env.DEV) { + whyDidYouRender(React, { + trackAllPureComponents: true, + trackExtraHooks: [[ReactRedux, 'useSelector']], + logOwnerReasons: true, + logOnDifferentValues: true, + }) +} diff --git a/tsconfig.json b/tsconfig.json index 26277df31c..8094043b36 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,7 +25,10 @@ "types": ["vite/client", "vite-plugin-svgr/client"], "typeRoots": ["./types"], "baseUrl": "src", - "useUnknownInCatchVariables": false + "useUnknownInCatchVariables": false, + "paths": { + "@/*": ["./src/*"] + } }, "exclude": ["node_modules", "cypress"], "include": ["./src/**/*.ts", "./src/**/*.tsx"] diff --git a/vite.config.ts b/vite.config.ts index e58c3226cb..6f9cf965cf 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,6 +1,7 @@ import GlobalPolyFill from '@esbuild-plugins/node-globals-polyfill' import lingui from '@lingui/vite-plugin' import react from '@vitejs/plugin-react' +import path from 'path' import { defineConfig } from 'vite' import checker from 'vite-plugin-checker' import svgrPlugin from 'vite-plugin-svgr' @@ -13,6 +14,7 @@ export default defineConfig({ }, plugins: [ react({ + jsxImportSource: '@welldone-software/why-did-you-render', babel: { // Use .babelrc files, necessary to use LinguiJS CLI babelrc: true, @@ -53,6 +55,9 @@ export default defineConfig({ stream: 'stream-browserify', zlib: 'browserify-zlib', util: 'util', + 'react-redux': 'react-redux/dist/react-redux.js', + '@': path.resolve(__dirname, './src/'), + "react-dom/client": "react-dom/profiling", }, }, server: { diff --git a/yarn.lock b/yarn.lock index 28c71e35de..7ddf7f4678 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,15 +22,7 @@ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.4.tgz#aae21cb858bbb0411949d5b7b3051f4209043f62" integrity sha512-UK0bHA7hh9cR39V+4gl2/NnBBjoXIxkuWAPCaY4X7fbH4L/azIi7ilWOCjMUYfpJgraLUAqkRi2BqrjME8Rynw== -"@ampproject/remapping@^2.1.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== - dependencies: - "@jridgewell/gen-mapping" "^0.1.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@ampproject/remapping@^2.2.0": +"@ampproject/remapping@^2.1.0", "@ampproject/remapping@^2.2.0": version "2.2.1" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== @@ -62,14 +54,14 @@ tslib "^2.3.0" zen-observable-ts "^1.2.5" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.21.4": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.21.4": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39" integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== dependencies: "@babel/highlight" "^7.18.6" -"@babel/code-frame@^7.22.13": +"@babel/code-frame@^7.16.7", "@babel/code-frame@^7.22.13": version "7.22.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== @@ -159,7 +151,7 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.11.6", "@babel/generator@^7.17.3", "@babel/generator@^7.17.7", "@babel/generator@^7.22.0": +"@babel/generator@^7.11.6", "@babel/generator@^7.22.0": version "7.22.3" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.3.tgz#0ff675d2edb93d7596c5f6728b52615cfc0df01e" integrity sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A== @@ -169,7 +161,7 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" -"@babel/generator@^7.22.15": +"@babel/generator@^7.17.3", "@babel/generator@^7.17.7", "@babel/generator@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339" integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA== @@ -186,18 +178,7 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.22.1": - version "7.22.1" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.1.tgz#bfcd6b7321ffebe33290d68550e2c9d7eb7c7a58" - integrity sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ== - dependencies: - "@babel/compat-data" "^7.22.0" - "@babel/helper-validator-option" "^7.21.0" - browserslist "^4.21.3" - lru-cache "^5.1.1" - semver "^6.3.0" - -"@babel/helper-compilation-targets@^7.22.15": +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== @@ -208,6 +189,17 @@ lru-cache "^5.1.1" semver "^6.3.1" +"@babel/helper-compilation-targets@^7.22.1": + version "7.22.1" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.1.tgz#bfcd6b7321ffebe33290d68550e2c9d7eb7c7a58" + integrity sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ== + dependencies: + "@babel/compat-data" "^7.22.0" + "@babel/helper-validator-option" "^7.21.0" + browserslist "^4.21.3" + lru-cache "^5.1.1" + semver "^6.3.0" + "@babel/helper-create-class-features-plugin@^7.21.0": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.4.tgz#3a017163dc3c2ba7deb9a7950849a9586ea24c18" @@ -222,17 +214,25 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" "@babel/helper-split-export-declaration" "^7.18.6" -"@babel/helper-environment-visitor@^7.16.7", "@babel/helper-environment-visitor@^7.18.9", "@babel/helper-environment-visitor@^7.22.1": +"@babel/helper-environment-visitor@^7.16.7", "@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== + +"@babel/helper-environment-visitor@^7.18.9", "@babel/helper-environment-visitor@^7.22.1": version "7.22.1" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.1.tgz#ac3a56dbada59ed969d712cf527bd8271fe3eba8" integrity sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA== -"@babel/helper-environment-visitor@^7.22.5": +"@babel/helper-function-name@^7.16.7", "@babel/helper-function-name@^7.22.5": version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" - integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + dependencies: + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" -"@babel/helper-function-name@^7.16.7", "@babel/helper-function-name@^7.21.0": +"@babel/helper-function-name@^7.21.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== @@ -240,28 +240,20 @@ "@babel/template" "^7.20.7" "@babel/types" "^7.21.0" -"@babel/helper-function-name@^7.22.5": +"@babel/helper-hoist-variables@^7.16.7", "@babel/helper-hoist-variables@^7.22.5": version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" - integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== dependencies: - "@babel/template" "^7.22.5" "@babel/types" "^7.22.5" -"@babel/helper-hoist-variables@^7.16.7", "@babel/helper-hoist-variables@^7.18.6": +"@babel/helper-hoist-variables@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== dependencies: "@babel/types" "^7.18.6" -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - "@babel/helper-member-expression-to-functions@^7.20.7", "@babel/helper-member-expression-to-functions@^7.21.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz#319c6a940431a133897148515877d2f3269c3ba5" @@ -283,7 +275,18 @@ dependencies: "@babel/types" "^7.22.15" -"@babel/helper-module-transforms@^7.17.7", "@babel/helper-module-transforms@^7.21.2", "@babel/helper-module-transforms@^7.22.1": +"@babel/helper-module-transforms@^7.17.7": + version "7.22.17" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz#7edf129097a51ccc12443adbc6320e90eab76693" + integrity sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.15" + +"@babel/helper-module-transforms@^7.21.2", "@babel/helper-module-transforms@^7.22.1": version "7.22.1" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.1.tgz#e0cad47fedcf3cae83c11021696376e2d5a50c63" integrity sha512-dxAe9E7ySDGbQdCVOY/4+UcD8M9ZFqZcZhSPsPacvCG4M+9lwtDDQfI2EoaSvmf7W/8yCBkGU0m7Pvt1ru3UZw== @@ -358,20 +361,20 @@ dependencies: "@babel/types" "^7.20.0" -"@babel/helper-split-export-declaration@^7.16.7", "@babel/helper-split-export-declaration@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" - integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-split-export-declaration@^7.22.6": +"@babel/helper-split-export-declaration@^7.16.7", "@babel/helper-split-export-declaration@^7.22.6": version "7.22.6" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== dependencies: "@babel/types" "^7.22.5" +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + "@babel/helper-string-parser@^7.19.4", "@babel/helper-string-parser@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" @@ -402,16 +405,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== -"@babel/helpers@^7.17.8", "@babel/helpers@^7.22.0": - version "7.22.3" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.3.tgz#53b74351da9684ea2f694bf0877998da26dd830e" - integrity sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w== - dependencies: - "@babel/template" "^7.21.9" - "@babel/traverse" "^7.22.1" - "@babel/types" "^7.22.3" - -"@babel/helpers@^7.22.15": +"@babel/helpers@^7.17.8", "@babel/helpers@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.15.tgz#f09c3df31e86e3ea0b7ff7556d85cdebd47ea6f1" integrity sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw== @@ -420,6 +414,15 @@ "@babel/traverse" "^7.22.15" "@babel/types" "^7.22.15" +"@babel/helpers@^7.22.0": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.3.tgz#53b74351da9684ea2f694bf0877998da26dd830e" + integrity sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w== + dependencies: + "@babel/template" "^7.21.9" + "@babel/traverse" "^7.22.1" + "@babel/types" "^7.22.3" + "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -448,10 +451,10 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.3.tgz#838ae31893373222cd9062568e2192c670037e00" integrity sha512-vrukxyW/ep8UD1UDzOYpTKQ6abgjFoeG6L+4ar9+c5TN9QnlqiOi6QK7LSR5ewm/ERyGkT/Ai6VboNrxhbr9Uw== -"@babel/parser@^7.16.4", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.5.tgz#7f3c7335fe417665d929f34ae5dceae4c04015e8" - integrity sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA== +"@babel/parser@^7.17.3", "@babel/parser@^7.17.8", "@babel/parser@^7.20.15", "@babel/parser@^7.21.3", "@babel/parser@^7.22.16": + version "7.22.16" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" + integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== "@babel/parser@^7.21.2": version "7.22.5" @@ -588,16 +591,7 @@ dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.16.7", "@babel/template@^7.20.7", "@babel/template@^7.21.9": - version "7.21.9" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.21.9.tgz#bf8dad2859130ae46088a99c1f265394877446fb" - integrity sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ== - dependencies: - "@babel/code-frame" "^7.21.4" - "@babel/parser" "^7.21.9" - "@babel/types" "^7.21.5" - -"@babel/template@^7.22.15", "@babel/template@^7.22.5": +"@babel/template@^7.16.7", "@babel/template@^7.22.15", "@babel/template@^7.22.5": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== @@ -606,6 +600,15 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" +"@babel/template@^7.20.7", "@babel/template@^7.21.9": + version "7.21.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.21.9.tgz#bf8dad2859130ae46088a99c1f265394877446fb" + integrity sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ== + dependencies: + "@babel/code-frame" "^7.21.4" + "@babel/parser" "^7.21.9" + "@babel/types" "^7.21.5" + "@babel/traverse@7.17.3": version "7.17.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" @@ -622,7 +625,23 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/traverse@^7.17.3", "@babel/traverse@^7.20.7", "@babel/traverse@^7.22.1", "@babel/traverse@^7.4.5": +"@babel/traverse@^7.17.3": + version "7.22.17" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.17.tgz#b23c203ab3707e3be816043081b4a994fcacec44" + integrity sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.22.15" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.16" + "@babel/types" "^7.22.17" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/traverse@^7.20.7", "@babel/traverse@^7.22.1", "@babel/traverse@^7.4.5": version "7.22.1" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.1.tgz#bd22c50b1439cfcfc2fa137b7fdf6c06787456e9" integrity sha512-lAWkdCoUFnmwLBhIRLciFntGYsIIoC6vIbN8zrLPqBnJmPu7Z6nzqnKd7FsxQUNAvZfVZ0x6KdNvNp8zWIOHSQ== @@ -671,7 +690,7 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" -"@babel/types@^7.11.5", "@babel/types@^7.17.0", "@babel/types@^7.18.6", "@babel/types@^7.20.0", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.4", "@babel/types@^7.21.5", "@babel/types@^7.22.0", "@babel/types@^7.22.3": +"@babel/types@^7.11.5", "@babel/types@^7.18.6", "@babel/types@^7.20.0", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.4", "@babel/types@^7.21.5", "@babel/types@^7.22.0", "@babel/types@^7.22.3": version "7.22.3" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.3.tgz#0cc6af178b91490acaeb4a2f70dcbf27cdf3d8f3" integrity sha512-P3na3xIQHTKY4L0YOG7pM8M8uoUIB910WQaSiiMCZUC2Cy8XFEQONGABFnHWBa2gpGKODTAJcNhi5Zk0sLRrzg== @@ -680,6 +699,15 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" +"@babel/types@^7.17.0", "@babel/types@^7.22.17": + version "7.22.17" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.17.tgz#f753352c4610ffddf9c8bc6823f9ff03e2303eee" + integrity sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.15" + to-fast-properties "^2.0.0" + "@babel/types@^7.22.15", "@babel/types@^7.22.5": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.15.tgz#266cb21d2c5fd0b3931e7a91b6dd72d2f617d282" @@ -2102,14 +2130,6 @@ "@walletconnect/utils" "2.0.0-rc.3" bs58 "^5.0.0" -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" @@ -2129,7 +2149,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== -"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": +"@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== @@ -2147,7 +2167,7 @@ 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": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.15": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -5257,63 +5277,63 @@ magic-string "^0.27.0" react-refresh "^0.14.0" -"@vue/compiler-core@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.45.tgz#d9311207d96f6ebd5f4660be129fb99f01ddb41b" - integrity sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A== +"@vue/compiler-core@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.3.4.tgz#7fbf591c1c19e1acd28ffd284526e98b4f581128" + integrity sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g== dependencies: - "@babel/parser" "^7.16.4" - "@vue/shared" "3.2.45" + "@babel/parser" "^7.21.3" + "@vue/shared" "3.3.4" estree-walker "^2.0.2" - source-map "^0.6.1" + source-map-js "^1.0.2" -"@vue/compiler-dom@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz#c43cc15e50da62ecc16a42f2622d25dc5fd97dce" - integrity sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw== +"@vue/compiler-dom@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz#f56e09b5f4d7dc350f981784de9713d823341151" + integrity sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w== dependencies: - "@vue/compiler-core" "3.2.45" - "@vue/shared" "3.2.45" + "@vue/compiler-core" "3.3.4" + "@vue/shared" "3.3.4" "@vue/compiler-sfc@^3.2.40": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz#7f7989cc04ec9e7c55acd406827a2c4e96872c70" - integrity sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q== - dependencies: - "@babel/parser" "^7.16.4" - "@vue/compiler-core" "3.2.45" - "@vue/compiler-dom" "3.2.45" - "@vue/compiler-ssr" "3.2.45" - "@vue/reactivity-transform" "3.2.45" - "@vue/shared" "3.2.45" + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz#b19d942c71938893535b46226d602720593001df" + integrity sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ== + dependencies: + "@babel/parser" "^7.20.15" + "@vue/compiler-core" "3.3.4" + "@vue/compiler-dom" "3.3.4" + "@vue/compiler-ssr" "3.3.4" + "@vue/reactivity-transform" "3.3.4" + "@vue/shared" "3.3.4" estree-walker "^2.0.2" - magic-string "^0.25.7" + magic-string "^0.30.0" postcss "^8.1.10" - source-map "^0.6.1" + source-map-js "^1.0.2" -"@vue/compiler-ssr@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz#bd20604b6e64ea15344d5b6278c4141191c983b2" - integrity sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ== +"@vue/compiler-ssr@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz#9d1379abffa4f2b0cd844174ceec4a9721138777" + integrity sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ== dependencies: - "@vue/compiler-dom" "3.2.45" - "@vue/shared" "3.2.45" + "@vue/compiler-dom" "3.3.4" + "@vue/shared" "3.3.4" -"@vue/reactivity-transform@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz#07ac83b8138550c83dfb50db43cde1e0e5e8124d" - integrity sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ== +"@vue/reactivity-transform@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz#52908476e34d6a65c6c21cd2722d41ed8ae51929" + integrity sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw== dependencies: - "@babel/parser" "^7.16.4" - "@vue/compiler-core" "3.2.45" - "@vue/shared" "3.2.45" + "@babel/parser" "^7.20.15" + "@vue/compiler-core" "3.3.4" + "@vue/shared" "3.3.4" estree-walker "^2.0.2" - magic-string "^0.25.7" + magic-string "^0.30.0" -"@vue/shared@3.2.45": - version "3.2.45" - resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.45.tgz#a3fffa7489eafff38d984e23d0236e230c818bc2" - integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg== +"@vue/shared@3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.3.4.tgz#06e83c5027f464eef861c329be81454bc8b70780" + integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ== "@walletconnect/browser-utils@^1.8.0": version "1.8.0" @@ -5843,6 +5863,13 @@ motion "10.16.2" qrcode "1.5.3" +"@welldone-software/why-did-you-render@^7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@welldone-software/why-did-you-render/-/why-did-you-render-7.0.1.tgz#09f487d84844bd8e66435843c2e0305702e61efb" + integrity sha512-Qe/8Xxa2G+LMdI6VoazescPzjjkHYduCDa8aHOJR50e9Bgs8ihkfMBY+ev7B4oc3N59Zm547Sgjf8h5y0FOyoA== + dependencies: + lodash "^4" + "@wojtekmaj/date-utils@^1.0.2", "@wojtekmaj/date-utils@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@wojtekmaj/date-utils/-/date-utils-1.0.3.tgz#2dcfd92881425c5923e429c2aec86fb3609032a1" @@ -12480,7 +12507,7 @@ lodash.upperfirst@4.3.1: resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== -lodash@4.17.21, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4: +lodash@4.17.21, lodash@^4, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -12579,13 +12606,6 @@ macos-release@^3.1.0: resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-3.1.0.tgz#6165bb0736ae567ed6649e36ce6a24d87cbb7aca" integrity sha512-/M/R0gCDgM+Cv1IuBG1XGdfTFnMEG6PZeT+KGWHO/OG+imqmaD9CH5vHBTycEM3+Kc4uG2Il+tFAuUWLqQOeUA== -magic-string@^0.25.7: - version "0.25.9" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" - integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== - dependencies: - sourcemap-codec "^1.4.8" - magic-string@^0.27.0: version "0.27.0" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3" @@ -12593,6 +12613,13 @@ magic-string@^0.27.0: dependencies: "@jridgewell/sourcemap-codec" "^1.4.13" +magic-string@^0.30.0: + version "0.30.3" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.3.tgz#403755dfd9d6b398dfa40635d52e96c5ac095b85" + integrity sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + make-dir@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" @@ -12989,11 +13016,6 @@ nano-css@^5.2.1: stacktrace-js "^2.0.2" stylis "^4.0.6" -nanoid@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" - integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== - nanoid@^3.3.6: version "3.3.6" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" @@ -14110,11 +14132,11 @@ postcss@^7.0.2: source-map "^0.6.1" postcss@^8.1.10: - version "8.4.20" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.20.tgz#64c52f509644cecad8567e949f4081d98349dc56" - integrity sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g== + version "8.4.29" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd" + integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw== dependencies: - nanoid "^3.3.4" + nanoid "^3.3.6" picocolors "^1.0.0" source-map-js "^1.0.2"