Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: release v1.589.0 #6830

Merged
merged 10 commits into from
May 7, 2024
25 changes: 25 additions & 0 deletions .github/workflows/sentry.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: New Sentry Release
on:
pull_request:
branches: [main]

jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout release
- uses: actions/checkout@v3
with:
ref: release
- name: Sentry Release
uses: getsentry/action-release@v1.7.0
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
with:
environment: production
# uses the release PR title as a version
version: ${{ github.event.pull_request.title }}
ignore_missing: true

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

102 changes: 39 additions & 63 deletions scripts/generateAssetData/colorMap/color-map.json

Large diffs are not rendered by default.

125 changes: 96 additions & 29 deletions src/components/ManageAccountsDrawer/components/ImportAccounts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from '@chakra-ui/react'
import type { ChainId } from '@shapeshiftoss/caip'
import { type AccountId, fromAccountId } from '@shapeshiftoss/caip'
import type { Asset } from '@shapeshiftoss/types'
import type { AccountMetadata, Asset } from '@shapeshiftoss/types'
import { useIsFetching, useQuery, useQueryClient } from '@tanstack/react-query'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslate } from 'react-polyglot'
Expand All @@ -21,14 +21,18 @@ import { accountManagement } from 'react-queries/queries/accountManagement'
import { Amount } from 'components/Amount/Amount'
import { MiddleEllipsis } from 'components/MiddleEllipsis/MiddleEllipsis'
import { RawText } from 'components/Text'
import { useToggle } from 'hooks/useToggle/useToggle'
import { useWallet } from 'hooks/useWallet/useWallet'
import { isUtxoAccountId } from 'lib/utils/utxo'
import { portfolio, portfolioApi } from 'state/slices/portfolioSlice/portfolioSlice'
import { accountIdToLabel } from 'state/slices/portfolioSlice/utils'
import {
selectFeeAssetByChainId,
selectHighestAccountNumberForChainId,
selectIsAccountIdEnabled,
selectPortfolioCryptoPrecisionBalanceByFilter,
} from 'state/slices/selectors'
import { useAppSelector } from 'state/store'
import { useAppDispatch, useAppSelector } from 'state/store'

import { DrawerContentWrapper } from './DrawerContent'

Expand All @@ -45,18 +49,28 @@ type TableRowProps = {
accountId: AccountId
accountNumber: number
asset: Asset
toggleAccountId: (accountId: AccountId) => void
onAccountIdActiveChange: (accountId: AccountId, isActive: boolean) => void
}

const disabledProp = { opacity: 0.5, cursor: 'not-allowed', userSelect: 'none' }
const disabledProps = { opacity: 0.5, cursor: 'not-allowed', userSelect: 'none' }

const TableRow = forwardRef<TableRowProps, 'div'>(
({ asset, accountId, accountNumber, toggleAccountId }, ref) => {
({ asset, accountId, accountNumber, onAccountIdActiveChange }, ref) => {
const translate = useTranslate()
const handleChange = useCallback(() => toggleAccountId(accountId), [accountId, toggleAccountId])
const accountLabel = useMemo(() => accountIdToLabel(accountId), [accountId])
const balanceFilter = useMemo(() => ({ assetId: asset.assetId, accountId }), [asset, accountId])
const isAccountEnabledFilter = useMemo(() => ({ accountId }), [accountId])
const isAccountEnabledInRedux = useAppSelector(state =>
selectIsAccountIdEnabled(state, isAccountEnabledFilter),
)

const [isAccountActive, toggleIsAccountActive] = useToggle(isAccountEnabledInRedux)

useEffect(() => {
onAccountIdActiveChange(accountId, isAccountActive)
}, [accountId, isAccountActive, isAccountEnabledInRedux, onAccountIdActiveChange])

// TODO: Redux wont have this for new accounts and will be 0, so we'll need to fetch it
const assetBalancePrecision = useAppSelector(s =>
selectPortfolioCryptoPrecisionBalanceByFilter(s, balanceFilter),
)
Expand All @@ -70,7 +84,7 @@ const TableRow = forwardRef<TableRowProps, 'div'>(
<RawText>{accountNumber}</RawText>
</Td>
<Td>
<Switch onChange={handleChange} />
<Switch isChecked={isAccountActive} onChange={toggleIsAccountActive} />
</Td>
<Td>
<Tooltip label={pubkey} isDisabled={isUtxoAccount}>
Expand Down Expand Up @@ -112,23 +126,33 @@ const LoadingRow = () => {

export const ImportAccounts = ({ chainId, onClose }: ImportAccountsProps) => {
const translate = useTranslate()
const wallet = useWallet().state.wallet
const dispatch = useAppDispatch()
const { wallet, deviceId: walletDeviceId } = useWallet().state
const asset = useAppSelector(state => selectFeeAssetByChainId(state, chainId))
const highestAccountNumberForChainIdFilter = useMemo(() => ({ chainId }), [chainId])
const highestAccountNumber = useAppSelector(state =>
selectHighestAccountNumberForChainId(state, highestAccountNumberForChainIdFilter),
)
const chainNamespaceDisplayName = asset?.networkName ?? ''
const [accounts, setAccounts] = useState<{ accountNumber: number; accountId: AccountId }[]>([])
const [accounts, setAccounts] = useState<
{ accountId: AccountId; accountMetadata: AccountMetadata; hasActivity: boolean }[]
>([])
const queryClient = useQueryClient()
const isLoading = useIsFetching({ queryKey: ['accountManagement'] }) > 0

// TODO:
// when "done" is clicked, all enabled accounts for this chain will be upserted into the portfolio
// all disabled ones will be removed.
// need to call dispatch(portfolioApi.getAccount({ accountId, upsertOnFetch: true }))
// which internally calls dispatch(portfolio.actions.upsertPortfolio(account)) and upserts assets
// But also need to remove accounts that were disabled.
const [accountIdActiveStateUpdate, setAccountIdActiveStateUpdate] = useState<
Record<string, boolean>
>({})

// initial fetch to detect the number of accounts based on the "first empty account" heuristic
const { data: allAccountIdsWithActivity } = useQuery(
accountManagement.allAccountIdsWithActivity(chainId, wallet, NUM_ADDITIONAL_EMPTY_ACCOUNTS),
accountManagement.firstAccountIdsWithActivityAndMetadata(
chainId,
wallet,
walletDeviceId,
// Account numbers are 0-indexed, so we need to add 1 to the highest account number.
// Add additional empty accounts to show more accounts without having to load more.
highestAccountNumber + 1 + NUM_ADDITIONAL_EMPTY_ACCOUNTS,
),
)

useEffect(() => {
Expand All @@ -139,31 +163,69 @@ export const ImportAccounts = ({ chainId, onClose }: ImportAccountsProps) => {
if (!wallet) return
const accountNumber = accounts.length
const accountResult = await queryClient.fetchQuery(
reactQueries.accountManagement.accountIdWithActivity(accountNumber, chainId, wallet),
reactQueries.accountManagement.accountIdWithActivityAndMetadata(
accountNumber,
chainId,
wallet,
walletDeviceId,
),
)
if (!accountResult) return
setAccounts(previousAccounts => {
const { accountId } = accountResult
return [...previousAccounts, { accountNumber, accountId }]
const { accountId, accountMetadata, hasActivity } = accountResult
return [...previousAccounts, { accountId, accountMetadata, hasActivity }]
})
}, [accounts, chainId, queryClient, wallet])
}, [accounts, chainId, queryClient, wallet, walletDeviceId])

const handleToggleAccountId = useCallback((accountId: AccountId) => {
console.log('handleToggleAccountId', accountId)
const handleAccountIdActiveChange = useCallback((accountId: AccountId, isActive: boolean) => {
setAccountIdActiveStateUpdate(previousState => {
return { ...previousState, [accountId]: isActive }
})
}, [])

// TODO: Loading state
const handleDone = useCallback(async () => {
// for every new account that is active, fetch the account and upsert it into the redux state
for (const [accountId, isActive] of Object.entries(accountIdActiveStateUpdate)) {
if (!isActive) continue
await dispatch(portfolioApi.endpoints.getAccount.initiate({ accountId, upsertOnFetch: true }))
}

const accountMetadataByAccountId = accounts.reduce(
(accumulator, { accountId, accountMetadata }) => {
return { ...accumulator, [accountId]: accountMetadata }
},
{},
)

dispatch(
portfolio.actions.upsertAccountMetadata({
accountMetadataByAccountId,
walletId: walletDeviceId,
}),
)

const hiddenAccountIds = Object.entries(accountIdActiveStateUpdate)
.filter(([_, isActive]) => !isActive)
.map(([accountId]) => accountId)

dispatch(portfolio.actions.setHiddenAccountIds(hiddenAccountIds))

onClose()
}, [accountIdActiveStateUpdate, accounts, dispatch, onClose, walletDeviceId])

const accountRows = useMemo(() => {
if (!asset) return null
return accounts.map(({ accountId, accountNumber }) => (
return accounts.map(({ accountId }, accountNumber) => (
<TableRow
key={accountId}
accountId={accountId}
accountNumber={accountNumber}
asset={asset}
toggleAccountId={handleToggleAccountId}
onAccountIdActiveChange={handleAccountIdActiveChange}
/>
))
}, [accounts, asset, handleToggleAccountId])
}, [accounts, asset, handleAccountIdActiveChange])

if (!asset) {
console.error(`No fee asset found for chainId: ${chainId}`)
Expand All @@ -181,11 +243,16 @@ export const ImportAccounts = ({ chainId, onClose }: ImportAccountsProps) => {
mr={3}
onClick={onClose}
isDisabled={isLoading}
_disabled={disabledProp}
_disabled={disabledProps}
>
{translate('common.cancel')}
</Button>
<Button colorScheme='blue' isDisabled={isLoading} _disabled={disabledProp}>
<Button
colorScheme='blue'
onClick={handleDone}
isDisabled={isLoading}
_disabled={disabledProps}
>
{translate('common.done')}
</Button>
</>
Expand All @@ -204,7 +271,7 @@ export const ImportAccounts = ({ chainId, onClose }: ImportAccountsProps) => {
colorScheme='gray'
onClick={handleLoadMore}
isDisabled={isLoading}
_disabled={disabledProp}
_disabled={disabledProps}
>
{translate('common.loadMore')}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ export const useFetchOpportunities = () => {
const portfolioAccounts = useSelector(selectPortfolioAccounts)
const DynamicLpAssets = useFeatureFlag('DynamicLpAssets')

const { isLoading: isZapperAppsBalancesOutputLoading } = useGetZapperAppsBalancesOutputQuery()
const { isLoading: isZapperAppsBalancesOutputLoading } = useGetZapperAppsBalancesOutputQuery(
undefined,
{
skip: !requestedAccountIds.length,
},
)
const { isLoading: isZapperUniV2PoolAssetIdsLoading } = useGetZapperUniV2PoolAssetIdsQuery(
undefined,
{ skip: !DynamicLpAssets },
Expand Down
6 changes: 2 additions & 4 deletions src/context/WalletProvider/Coinbase/components/Connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import type { ActionTypes } from 'context/WalletProvider/actions'
import { WalletActions } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import { removeAccountsAndChainListeners } from 'context/WalletProvider/WalletProvider'
import { useWallet } from 'hooks/useWallet/useWallet'
import { getEthersProvider } from 'lib/ethersProviderSingleton'

import { ConnectModal } from '../../components/ConnectModal'
import type { LocationState } from '../../NativeWallet/types'
Expand Down Expand Up @@ -40,9 +40,7 @@ export const CoinbaseConnect = ({ history }: CoinbaseSetupProps) => {
if (adapter) {
try {
// Remove all provider event listeners from previously connected wallets
const ethersProvider = getEthersProvider()
ethersProvider.removeAllListeners('accountsChanged')
ethersProvider.removeAllListeners('chainChanged')
await removeAccountsAndChainListeners()

const wallet = await adapter.pairDevice()
if (!wallet) {
Expand Down
6 changes: 2 additions & 4 deletions src/context/WalletProvider/KeepKey/components/Connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { Text } from 'components/Text'
import { WalletActions } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import { removeAccountsAndChainListeners } from 'context/WalletProvider/WalletProvider'
import { useWallet } from 'hooks/useWallet/useWallet'
import { getEthersProvider } from 'lib/ethersProviderSingleton'

import { KeepKeyConfig } from '../config'
import { FailureType, MessageType } from '../KeepKeyTypes'
Expand Down Expand Up @@ -60,9 +60,7 @@ export const KeepKeyConnect = () => {
const wallet = await (async () => {
try {
// Remove all provider event listeners from previously connected wallets
const ethersProvider = getEthersProvider()
ethersProvider.removeAllListeners('accountsChanged')
ethersProvider.removeAllListeners('chainChanged')
await removeAccountsAndChainListeners()

const sdk = await setupKeepKeySDK()

Expand Down
6 changes: 2 additions & 4 deletions src/context/WalletProvider/Keplr/components/Connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import type { ActionTypes } from 'context/WalletProvider/actions'
import { WalletActions } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import { removeAccountsAndChainListeners } from 'context/WalletProvider/WalletProvider'
import { useWallet } from 'hooks/useWallet/useWallet'
import { getEthersProvider } from 'lib/ethersProviderSingleton'

import { ConnectModal } from '../../components/ConnectModal'
import { KeplrConfig } from '../config'
Expand Down Expand Up @@ -33,9 +33,7 @@ export const KeplrConnect = ({ history }: KeplrSetupProps) => {
const adapter = await getAdapter(KeyManager.Keplr)
if (adapter) {
// Remove all provider event listeners from previously connected wallets
const ethersProvider = getEthersProvider()
ethersProvider.removeAllListeners('accountsChanged')
ethersProvider.removeAllListeners('chainChanged')
await removeAccountsAndChainListeners()

const wallet = await adapter.pairDevice()
if (!wallet) {
Expand Down
6 changes: 2 additions & 4 deletions src/context/WalletProvider/Ledger/components/Connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import type { ActionTypes } from 'context/WalletProvider/actions'
import { WalletActions } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import { removeAccountsAndChainListeners } from 'context/WalletProvider/WalletProvider'
import { useWallet } from 'hooks/useWallet/useWallet'
import { getEthersProvider } from 'lib/ethersProviderSingleton'

import { ConnectModal } from '../../components/ConnectModal'
import { LedgerConfig } from '../config'
Expand Down Expand Up @@ -37,9 +37,7 @@ export const LedgerConnect = ({ history }: LedgerSetupProps) => {
if (adapter) {
try {
// Remove all provider event listeners from previously connected wallets
const ethersProvider = getEthersProvider()
ethersProvider.removeAllListeners('accountsChanged')
ethersProvider.removeAllListeners('chainChanged')
await removeAccountsAndChainListeners()

const wallet = await adapter.pairDevice()

Expand Down
8 changes: 3 additions & 5 deletions src/context/WalletProvider/MetaMask/components/Connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { ActionTypes } from 'context/WalletProvider/actions'
import { WalletActions } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import { removeAccountsAndChainListeners } from 'context/WalletProvider/WalletProvider'
import { useFeatureFlag } from 'hooks/useFeatureFlag/useFeatureFlag'
import {
checkIsMetaMaskDesktop,
Expand All @@ -14,7 +15,6 @@ import {
checkIsSnapInstalled,
} from 'hooks/useIsSnapInstalled/useIsSnapInstalled'
import { useWallet } from 'hooks/useWallet/useWallet'
import { getEthersProvider } from 'lib/ethersProviderSingleton'
import { selectShowSnapsModal } from 'state/slices/selectors'

import { ConnectModal } from '../../components/ConnectModal'
Expand Down Expand Up @@ -52,10 +52,8 @@ export const MetaMaskConnect = ({ history }: MetaMaskSetupProps) => {

const adapter = await getAdapter(KeyManager.MetaMask)
if (adapter) {
const ethersProvider = getEthersProvider()
ethersProvider.removeAllListeners('accountsChanged')
ethersProvider.removeAllListeners('chainChanged')

// Remove all provider event listeners from previously connected wallets
await removeAccountsAndChainListeners()
const wallet = await adapter.pairDevice()
if (!wallet) {
setErrorLoading('walletProvider.errors.walletNotFound')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import { RawText, Text } from 'components/Text'
import { WalletActions } from 'context/WalletProvider/actions'
import { KeyManager } from 'context/WalletProvider/KeyManager'
import { useLocalWallet } from 'context/WalletProvider/local-wallet'
import { removeAccountsAndChainListeners } from 'context/WalletProvider/WalletProvider'
import { useWallet } from 'hooks/useWallet/useWallet'
import { getEthersProvider } from 'lib/ethersProviderSingleton'

import { MobileConfig } from '../config'
import { deleteWallet, getWallet, listWallets } from '../mobileMessageHandlers'
Expand Down Expand Up @@ -149,10 +149,8 @@ export const MobileLoad = ({ history }: RouteComponentProps) => {
if (!revoker?.mnemonic) throw new Error(`Mobile wallet not found: ${deviceId}`)
if (!revoker?.id) throw new Error(`Revoker ID not found: ${deviceId}`)

// remove all provider event listeners from previously connected wallets
const ethersProvider = getEthersProvider()
ethersProvider.removeAllListeners('accountsChanged')
ethersProvider.removeAllListeners('chainChanged')
// Remove all provider event listeners from previously connected wallets
await removeAccountsAndChainListeners()

const wallet = await adapter.pairDevice(revoker.id)
await wallet?.loadDevice({ mnemonic: revoker.mnemonic })
Expand Down
Loading
Loading