From 0575b65e8354be0c2f22e3e8664f3df53db6f180 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Thu, 20 Feb 2025 23:44:08 +0100 Subject: [PATCH 01/13] feat: non-null assert pass 1 (defi section) --- .eslintrc | 3 ++- .../UniV2Manager/Deposit/components/Approve.tsx | 14 +++++++++----- .../UniV2Manager/Withdraw/UniV2Withdraw.tsx | 2 +- .../UniV2Manager/Withdraw/components/Confirm.tsx | 2 +- .../UniV2Manager/Withdraw/components/Status.tsx | 2 +- src/state/apis/portals/portalsApi.ts | 2 +- .../opportunitiesSlice/resolvers/uniV2/index.ts | 14 +++++++------- .../opportunitiesSlice/selectors/lpSelectors.ts | 4 +++- 8 files changed, 25 insertions(+), 18 deletions(-) diff --git a/.eslintrc b/.eslintrc index 9d8cf0daac6..b591c375e56 100644 --- a/.eslintrc +++ b/.eslintrc @@ -97,7 +97,8 @@ "react/jsx-handler-names": "error", "require-await": "error", "import/no-duplicates": "error", - "react-memo/require-usememo": "error" + "react-memo/require-usememo": "error", + "@typescript-eslint/no-non-null-assertion": "warn" }, "overrides": [ { diff --git a/src/features/defi/providers/univ2/components/UniV2Manager/Deposit/components/Approve.tsx b/src/features/defi/providers/univ2/components/UniV2Manager/Deposit/components/Approve.tsx index ce4426c58e7..2b2e9ec4297 100644 --- a/src/features/defi/providers/univ2/components/UniV2Manager/Deposit/components/Approve.tsx +++ b/src/features/defi/providers/univ2/components/UniV2Manager/Deposit/components/Approve.tsx @@ -313,7 +313,7 @@ export const Approve: React.FC = ({ accountId, onNext }) => { = ({ accountId, onNext }) => { isApproved={isAsset0AllowanceGranted} loading={approve0Loading} preFooter={preFooter} - providerIcon={getMetadataForProvider(lpOpportunity!.provider)?.icon ?? ''} + providerIcon={ + lpOpportunity ? getMetadataForProvider(lpOpportunity.provider)?.icon : undefined + } onCancel={handleApproveCancel} // we need to pass an arg here, so we need an anonymous function wrapper // eslint-disable-next-line react-memo/require-usememo onConfirm={() => handleApprove(asset0ContractAddress)} - spenderContractAddress={UNISWAP_V2_ROUTER_02_CONTRACT_MAINNET!} + spenderContractAddress={UNISWAP_V2_ROUTER_02_CONTRACT_MAINNET} /> , ] @@ -342,7 +344,7 @@ export const Approve: React.FC = ({ accountId, onNext }) => { = ({ accountId, onNext }) => { isApproved={isAsset1AllowanceGranted} loading={approve1Loading} preFooter={preFooter} - providerIcon={getMetadataForProvider(lpOpportunity!.provider)?.icon ?? ''} + providerIcon={ + lpOpportunity ? getMetadataForProvider(lpOpportunity?.provider)?.icon : undefined + } onCancel={handleApproveCancel} // we need to pass an arg here, so we need an anonymous function wrapper // eslint-disable-next-line react-memo/require-usememo diff --git a/src/features/defi/providers/univ2/components/UniV2Manager/Withdraw/UniV2Withdraw.tsx b/src/features/defi/providers/univ2/components/UniV2Manager/Withdraw/UniV2Withdraw.tsx index 3058e900625..aa84420fbbc 100644 --- a/src/features/defi/providers/univ2/components/UniV2Manager/Withdraw/UniV2Withdraw.tsx +++ b/src/features/defi/providers/univ2/components/UniV2Manager/Withdraw/UniV2Withdraw.tsx @@ -118,7 +118,7 @@ export const UniV2Withdraw: React.FC = ({ diff --git a/src/features/defi/providers/univ2/components/UniV2Manager/Withdraw/components/Confirm.tsx b/src/features/defi/providers/univ2/components/UniV2Manager/Withdraw/components/Confirm.tsx index 05184c7ffd4..59ff8adf0d0 100644 --- a/src/features/defi/providers/univ2/components/UniV2Manager/Withdraw/components/Confirm.tsx +++ b/src/features/defi/providers/univ2/components/UniV2Manager/Withdraw/components/Confirm.tsx @@ -196,7 +196,7 @@ export const Confirm = ({ accountId, onNext }: ConfirmProps) => { = ({ accountId }) => { { - const underlyingAsset = assets[underlyingAssetId]! + const underlyingAsset = assets[underlyingAssetId] + + if (!underlyingAsset) return '0' return ( bnOrZero(lpAssetBalanceCryptoBaseUnit) From c599db0202a27e57c8cac7372a221e6bd5badc15 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Thu, 20 Feb 2025 23:45:18 +0100 Subject: [PATCH 02/13] [skip ci] chore: cancel CI From f722c3a1bb913d9a0cdb17fee42f33e1469a3b40 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 21 Feb 2025 00:17:36 +0100 Subject: [PATCH 03/13] [skip ci] feat: a few more bite the dust --- .../Deposit/ThorchainSaversDeposit.tsx | 24 ++++++----- .../Deposit/components/Confirm.tsx | 27 ++++++------ .../Deposit/components/Status.tsx | 4 +- .../Overview/ThorchainSaversOverview.tsx | 25 ++++++----- .../Withdraw/ThorchainSaversWithdraw.tsx | 43 +++++++++++-------- .../Withdraw/components/Confirm.tsx | 18 +++++--- .../Withdraw/components/Status.tsx | 4 +- .../Withdraw/components/Withdraw.tsx | 4 +- .../UniV2Manager/Deposit/UniV2Deposit.tsx | 2 +- src/lib/utils/thorchain/balance.ts | 4 +- 10 files changed, 92 insertions(+), 63 deletions(-) diff --git a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/ThorchainSaversDeposit.tsx b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/ThorchainSaversDeposit.tsx index aea69ec3d0b..d8f339dc514 100644 --- a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/ThorchainSaversDeposit.tsx +++ b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/ThorchainSaversDeposit.tsx @@ -2,7 +2,7 @@ import { Center } from '@chakra-ui/react' import type { AccountId } from '@shapeshiftoss/caip' import { thorchainAssetId, toAssetId, usdtAssetId } from '@shapeshiftoss/caip' import type { Asset } from '@shapeshiftoss/types' -import { useQuery } from '@tanstack/react-query' +import { skipToken, useQuery } from '@tanstack/react-query' import { DefiModalContent } from 'features/defi/components/DefiModal/DefiModalContent' import { DefiModalHeader } from 'features/defi/components/DefiModal/DefiModalHeader' import type { @@ -13,7 +13,6 @@ import { DefiAction, DefiStep } from 'features/defi/contexts/DefiManagerProvider import qs from 'qs' import { useCallback, useEffect, useMemo, useReducer } from 'react' import { useTranslate } from 'react-polyglot' -import { reactQueries } from 'react-queries' import { useSelector } from 'react-redux' import type { AccountDropdownProps } from 'components/AccountDropdown/AccountDropdown' import { CircularProgress } from 'components/CircularProgress/CircularProgress' @@ -22,6 +21,7 @@ import { Steps } from 'components/DeFi/components/Steps' import { Sweep } from 'components/Sweep' import { useBrowserRouter } from 'hooks/useBrowserRouter/useBrowserRouter' import { useWallet } from 'hooks/useWallet/useWallet' +import { getThorchainFromAddress } from 'lib/utils/thorchain' import { isUtxoChainId } from 'lib/utils/utxo' import { getThorchainSaversPosition } from 'state/slices/opportunitiesSlice/resolvers/thorchainsavers/utils' import type { StakingId } from 'state/slices/opportunitiesSlice/types' @@ -129,14 +129,18 @@ export const ThorchainSaversDeposit: React.FC = ({ ) const { data: fromAddress } = useQuery({ - ...reactQueries.common.thorchainFromAddress({ - accountId: accountId!, - getPosition: getThorchainSaversPosition, - assetId, - wallet: wallet!, - accountMetadata: accountMetadata!, - }), - enabled: Boolean(accountId && wallet && accountMetadata), + queryKey: ['thorchainFromAddress', accountId, assetId], + queryFn: + accountId && wallet && accountMetadata + ? () => + getThorchainFromAddress({ + accountId, + assetId, + getPosition: getThorchainSaversPosition, + accountMetadata, + wallet, + }) + : skipToken, }) const makeHandleSweepBack = useCallback( diff --git a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Confirm.tsx b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Confirm.tsx index 149ee36d9c8..e1f49a24235 100644 --- a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Confirm.tsx +++ b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Confirm.tsx @@ -15,7 +15,7 @@ import { supportsETH } from '@shapeshiftoss/hdwallet-core' import { SwapperName } from '@shapeshiftoss/swapper' import type { Asset } from '@shapeshiftoss/types' import { isUtxoChainId } from '@shapeshiftoss/utils' -import { useQuery } from '@tanstack/react-query' +import { skipToken, useQuery } from '@tanstack/react-query' import { Confirm as ReusableConfirm } from 'features/defi/components/Confirm/Confirm' import { Summary } from 'features/defi/components/Summary' import type { @@ -25,7 +25,6 @@ import type { import { DefiStep } from 'features/defi/contexts/DefiManagerProvider/DefiCommon' import { useCallback, useContext, useEffect, useMemo } from 'react' import { useTranslate } from 'react-polyglot' -import { reactQueries } from 'react-queries' import { useIsTradingActive } from 'react-queries/hooks/useIsTradingActive' import { Amount } from 'components/Amount/Amount' import { AssetIcon } from 'components/AssetIcon' @@ -43,7 +42,7 @@ import { fromBaseUnit, toBaseUnit } from 'lib/math' import { trackOpportunityEvent } from 'lib/mixpanel/helpers' import { getMixPanel } from 'lib/mixpanel/mixPanelSingleton' import { MixPanelEvent } from 'lib/mixpanel/types' -import { fromThorBaseUnit, toThorBaseUnit } from 'lib/utils/thorchain' +import { fromThorBaseUnit, getThorchainFromAddress, toThorBaseUnit } from 'lib/utils/thorchain' import { BASE_BPS_POINTS, RUNEPOOL_DEPOSIT_MEMO } from 'lib/utils/thorchain/constants' import { useGetThorchainSaversDepositQuoteQuery } from 'lib/utils/thorchain/hooks/useGetThorchainSaversDepositQuoteQuery' import { useSendThorTx } from 'lib/utils/thorchain/hooks/useSendThorTx' @@ -77,7 +76,7 @@ export const Confirm: React.FC = ({ accountId, onNext }) => { const opportunity = useMemo(() => state?.opportunity, [state]) const assets = useAppSelector(selectAssets) - const chainAdapter = getChainAdapterManager().get(chainId)! + const chainAdapter = getChainAdapterManager().get(chainId) const assetId = toAssetId({ chainId, @@ -181,14 +180,18 @@ export const Confirm: React.FC = ({ accountId, onNext }) => { ) const { data: fromAddress } = useQuery({ - ...reactQueries.common.thorchainFromAddress({ - accountId: accountId!, - assetId, - wallet: wallet!, - accountMetadata: accountMetadata!, - getPosition: getThorchainSaversPosition, - }), - enabled: Boolean(accountId && wallet && accountMetadata), + queryKey: ['thorchainFromAddress', accountId, assetId], + queryFn: + accountId && wallet && accountMetadata + ? () => + getThorchainFromAddress({ + accountId, + assetId, + getPosition: getThorchainSaversPosition, + accountMetadata, + wallet, + }) + : skipToken, }) const memo = useMemo(() => { diff --git a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Status.tsx b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Status.tsx index d44189671b8..23a9b1ae856 100644 --- a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Status.tsx +++ b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Status.tsx @@ -72,9 +72,11 @@ export const Status: React.FC = ({ accountId }) => { useEffect(() => { if (!(contextDispatch && state?.txid?.length && accountId)) return ;(async () => { + if (!state?.txid) return + // Skipping outbound detection since there's no outbound tx involved here - as long as the inner swap is confirmed, we're gucci const thorchainTxStatus = await waitForThorchainUpdate({ - txId: state.txid!, + txId: state.txid, skipOutbound: true, }).promise diff --git a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Overview/ThorchainSaversOverview.tsx b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Overview/ThorchainSaversOverview.tsx index e8ba048dd48..89c6be65835 100644 --- a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Overview/ThorchainSaversOverview.tsx +++ b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Overview/ThorchainSaversOverview.tsx @@ -17,7 +17,7 @@ import { thorchainAssetId, toAssetId } from '@shapeshiftoss/caip' import { SwapperName } from '@shapeshiftoss/swapper' import type { Asset } from '@shapeshiftoss/types' import { TxStatus } from '@shapeshiftoss/unchained-client' -import { useQuery } from '@tanstack/react-query' +import { skipToken, useQuery } from '@tanstack/react-query' import BigNumber from 'bignumber.js' import type { DefiButtonProps } from 'features/defi/components/DefiActionButtons' import { Overview } from 'features/defi/components/Overview/Overview' @@ -29,7 +29,6 @@ import { DefiAction } from 'features/defi/contexts/DefiManagerProvider/DefiCommo import { useCallback, useEffect, useMemo, useState } from 'react' import { FaTwitter } from 'react-icons/fa' import { useTranslate } from 'react-polyglot' -import { reactQueries } from 'react-queries' import { useIsTradingActive } from 'react-queries/hooks/useIsTradingActive' import type { AccountDropdownProps } from 'components/AccountDropdown/AccountDropdown' import { Amount } from 'components/Amount/Amount' @@ -41,6 +40,7 @@ import { useFeatureFlag } from 'hooks/useFeatureFlag/useFeatureFlag' import { useWallet } from 'hooks/useWallet/useWallet' import { bnOrZero } from 'lib/bignumber/bignumber' import { fromBaseUnit, toBaseUnit } from 'lib/math' +import { getThorchainFromAddress } from 'lib/utils/thorchain' import { useGetThorchainSaversDepositQuoteQuery } from 'lib/utils/thorchain/hooks/useGetThorchainSaversDepositQuoteQuery' import { formatSecondsToDuration } from 'lib/utils/time' import { useIsLendingActive } from 'pages/Lending/hooks/useIsLendingActive' @@ -253,14 +253,19 @@ export const ThorchainSaversOverview: React.FC = ({ ) const { data: fromAddress } = useQuery({ - ...reactQueries.common.thorchainFromAddress({ - accountId: accountId!, - assetId, - wallet: wallet!, - accountMetadata: accountMetadata!, - getPosition: getThorchainSaversPosition, - }), - enabled: Boolean(accountId && wallet && accountMetadata), + queryKey: ['thorchainFromAddress', accountId, assetId, opportunityId], + queryFn: + accountId && wallet && accountMetadata + ? () => + getThorchainFromAddress({ + accountId, + assetId, + opportunityId, + getPosition: getThorchainSaversPosition, + accountMetadata, + wallet, + }) + : skipToken, }) const makeDefaultMenu = useCallback( diff --git a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/ThorchainSaversWithdraw.tsx b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/ThorchainSaversWithdraw.tsx index f98573d3bb9..ba7b96a6da2 100644 --- a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/ThorchainSaversWithdraw.tsx +++ b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/ThorchainSaversWithdraw.tsx @@ -2,7 +2,7 @@ import { Center } from '@chakra-ui/react' import type { AccountId } from '@shapeshiftoss/caip' import { thorchainAssetId, toAssetId } from '@shapeshiftoss/caip' import { isUtxoChainId } from '@shapeshiftoss/utils' -import { useQuery } from '@tanstack/react-query' +import { skipToken, useQuery } from '@tanstack/react-query' import { DefiModalContent } from 'features/defi/components/DefiModal/DefiModalContent' import { DefiModalHeader } from 'features/defi/components/DefiModal/DefiModalHeader' import type { @@ -13,7 +13,6 @@ import { DefiAction, DefiStep } from 'features/defi/contexts/DefiManagerProvider import qs from 'qs' import { useCallback, useEffect, useMemo, useReducer } from 'react' import { useTranslate } from 'react-polyglot' -import { reactQueries } from 'react-queries' import type { AccountDropdownProps } from 'components/AccountDropdown/AccountDropdown' import { CircularProgress } from 'components/CircularProgress/CircularProgress' import type { DefiStepProps, StepComponentProps } from 'components/DeFi/components/Steps' @@ -21,6 +20,7 @@ import { Steps } from 'components/DeFi/components/Steps' import { Sweep } from 'components/Sweep' import { useBrowserRouter } from 'hooks/useBrowserRouter/useBrowserRouter' import { useWallet } from 'hooks/useWallet/useWallet' +import { getThorchainFromAddress } from 'lib/utils/thorchain' import { getThorchainSaversPosition } from 'state/slices/opportunitiesSlice/resolvers/thorchainsavers/utils' import { serializeUserStakingId, toOpportunityId } from 'state/slices/opportunitiesSlice/utils' import { @@ -74,22 +74,26 @@ export const ThorchainSaversWithdraw: React.FC = ({ accountId }) const highestBalanceAccountId = useAppSelector(state => selectHighestStakingBalanceAccountIdByStakingId(state, highestBalanceAccountIdFilter), ) - const opportunityDataFilter = useMemo( - () => ({ + const opportunityDataFilter = useMemo(() => { + const _accountId = accountId ?? highestBalanceAccountId + if (!_accountId) return + + return { userStakingId: serializeUserStakingId( - (accountId ?? highestBalanceAccountId)!, + _accountId, toOpportunityId({ chainId, assetNamespace, assetReference, }), ), - }), - [accountId, assetNamespace, assetReference, chainId, highestBalanceAccountId], - ) + } + }, [accountId, assetNamespace, assetReference, chainId, highestBalanceAccountId]) const opportunityData = useAppSelector(state => - selectEarnUserStakingOpportunityByUserStakingId(state, opportunityDataFilter), + opportunityDataFilter + ? selectEarnUserStakingOpportunityByUserStakingId(state, opportunityDataFilter) + : undefined, ) // user info @@ -103,14 +107,19 @@ export const ThorchainSaversWithdraw: React.FC = ({ accountId }) ) const { data: fromAddress } = useQuery({ - ...reactQueries.common.thorchainFromAddress({ - accountId: accountId!, - getPosition: getThorchainSaversPosition, - assetId, - wallet: wallet!, - accountMetadata: accountMetadata!, - }), - enabled: Boolean(accountId && wallet && accountMetadata), + queryKey: ['thorchainFromAddress', accountId, assetId, opportunityId], + queryFn: + accountId && wallet && accountMetadata + ? () => + getThorchainFromAddress({ + accountId, + assetId, + opportunityId, + getPosition: getThorchainSaversPosition, + accountMetadata, + wallet, + }) + : skipToken, }) useEffect(() => { diff --git a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Confirm.tsx b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Confirm.tsx index 2d55133b787..1e3403c1e31 100644 --- a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Confirm.tsx +++ b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Confirm.tsx @@ -107,22 +107,26 @@ export const Confirm: React.FC = ({ accountId, onNext }) => { const highestBalanceAccountId = useAppSelector(state => selectHighestStakingBalanceAccountIdByStakingId(state, highestBalanceAccountIdFilter), ) - const opportunityDataFilter = useMemo( - () => ({ + const opportunityDataFilter = useMemo(() => { + const _accountId = accountId ?? highestBalanceAccountId + if (!_accountId) return + + return { userStakingId: serializeUserStakingId( - (accountId ?? highestBalanceAccountId)!, + _accountId, toOpportunityId({ chainId, assetNamespace, assetReference, }), ), - }), - [accountId, assetNamespace, assetReference, chainId, highestBalanceAccountId], - ) + } + }, [accountId, assetNamespace, assetReference, chainId, highestBalanceAccountId]) const opportunityData = useAppSelector(state => - selectEarnUserStakingOpportunityByUserStakingId(state, opportunityDataFilter), + opportunityDataFilter + ? selectEarnUserStakingOpportunityByUserStakingId(state, opportunityDataFilter) + : undefined, ) const asset = useAppSelector(state => selectAssetById(state, assetId ?? '')) diff --git a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Status.tsx b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Status.tsx index 88db8d45135..463cd601dcb 100644 --- a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Status.tsx +++ b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Status.tsx @@ -73,10 +73,12 @@ export const Status: React.FC = ({ accountId }) => { useEffect(() => { if (!(contextDispatch && state?.txid?.length && accountId)) return ;(async () => { + if (!state.txid) return + // Ensuring we wait for the outbound Tx to exist // Note, the transaction we wait for here is a Thorchain transaction, *not* the inbound Tx const thorchainTxStatus = await waitForThorchainUpdate({ - txId: state.txid!, + txId: state.txid, // RUNEPool has no outbound Tx so we skipOutbound, else this will spin to infinity skipOutbound: isRunePool, }).promise diff --git a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Withdraw.tsx b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Withdraw.tsx index e1e90be1961..06ccff66ad7 100644 --- a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Withdraw.tsx +++ b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Withdraw/components/Withdraw.tsx @@ -413,7 +413,7 @@ export const Withdraw: React.FC = ({ accountId, fromAddress, onNe fromAddress, }) - if (bnOrZero(missingFunds).gt(0)) setMissingFunds(missingFunds!.toFixed()) + if (bnOrZero(missingFunds).gt(0)) setMissingFunds(missingFunds.toFixed()) return ( balanceCryptoPrecision.gt(0) && @@ -518,7 +518,7 @@ export const Withdraw: React.FC = ({ accountId, fromAddress, onNe fromAddress, }) - if (bnOrZero(missingFunds).gt(0)) setMissingFunds(missingFunds!.toFixed()) + if (bnOrZero(missingFunds).gt(0)) setMissingFunds(missingFunds.toFixed()) return ( amountAvailableFiat.gt(0) && diff --git a/src/features/defi/providers/univ2/components/UniV2Manager/Deposit/UniV2Deposit.tsx b/src/features/defi/providers/univ2/components/UniV2Manager/Deposit/UniV2Deposit.tsx index d19135e12db..79177424d30 100644 --- a/src/features/defi/providers/univ2/components/UniV2Manager/Deposit/UniV2Deposit.tsx +++ b/src/features/defi/providers/univ2/components/UniV2Manager/Deposit/UniV2Deposit.tsx @@ -125,7 +125,7 @@ export const UniV2Deposit: React.FC = ({ diff --git a/src/lib/utils/thorchain/balance.ts b/src/lib/utils/thorchain/balance.ts index 3950afd06a9..f3f7dcd8390 100644 --- a/src/lib/utils/thorchain/balance.ts +++ b/src/lib/utils/thorchain/balance.ts @@ -1,7 +1,7 @@ import type { AccountId } from '@shapeshiftoss/caip' import type { Asset } from '@shapeshiftoss/types' import { queryClient } from 'context/QueryClientProvider/queryClient' -import { bnOrZero } from 'lib/bignumber/bignumber' +import { bn, bnOrZero } from 'lib/bignumber/bignumber' import { fromBaseUnit, toBaseUnit } from 'lib/math' import type { EstimatedFeesQueryKey } from 'pages/Lending/hooks/useGetEstimatedFeesQuery' import { queryFn as getEstimatedFeesQueryFn } from 'pages/Lending/hooks/useGetEstimatedFeesQuery' @@ -57,7 +57,7 @@ const getHasEnoughBalanceForTxPlusFeesPlusSweep = ({ sweepTxFeeCryptoBaseUnit: string }) => { const balanceCryptoBaseUnitBn = bnOrZero(balanceCryptoBaseUnit) - if (balanceCryptoBaseUnitBn.isZero()) return { hasEnoughBalance: false, missingFunds: null } + if (balanceCryptoBaseUnitBn.isZero()) return { hasEnoughBalance: false, missingFunds: bn(0) } return { hasEnoughBalance: bnOrZero(amountCryptoPrecision) From beba6fe2e2f40b04b4ed443d06fcd27c6b94c079 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 21 Feb 2025 12:33:06 +0100 Subject: [PATCH 04/13] feat: done --- .../defi/components/Deposit/Deposit.tsx | 2 +- .../CosmosManager/Overview/CosmosOverview.tsx | 2 +- .../FoxFarmingManager/Claim/ClaimStatus.tsx | 10 ++++-- .../Deposit/components/Confirm.tsx | 2 +- .../Deposit/components/Status.tsx | 2 +- .../Overview/FoxFarmingOverview.tsx | 22 +++++++----- .../Withdraw/FoxFarmingWithdraw.tsx | 16 +++++---- .../Withdraw/components/Confirm.tsx | 2 +- .../Withdraw/components/Status.tsx | 2 +- src/lib/portals/utils.ts | 2 +- .../hooks/useThorchainFromAddress.tsx | 26 ++++++++------ src/lib/utils/thorchain/index.ts | 11 ++++-- .../components/AddLiquidity/AddLiquidity.tsx | 3 +- .../AddLiquidity/AddLiquidityInput.tsx | 10 +++--- .../RemoveLiquidity/RemoveLiquidity.tsx | 5 +-- .../RemoveLiquidity/RemoveLiquidityInput.tsx | 33 ++++++++++-------- .../ReusableLpStatus/TransactionRow.tsx | 34 +++++++++++-------- .../resolvers/uniV2/index.ts | 2 +- 18 files changed, 111 insertions(+), 75 deletions(-) diff --git a/src/features/defi/components/Deposit/Deposit.tsx b/src/features/defi/components/Deposit/Deposit.tsx index 4aa71f627ec..234d1be2714 100644 --- a/src/features/defi/components/Deposit/Deposit.tsx +++ b/src/features/defi/components/Deposit/Deposit.tsx @@ -106,7 +106,7 @@ export const Deposit = ({ }, }) - const handleMaxClick = useCallback(() => onMaxClick!(setValue), [onMaxClick, setValue]) + const handleMaxClick = useCallback(() => onMaxClick?.(setValue), [onMaxClick, setValue]) const values = useWatch({ control }) const { field: cryptoAmount } = useController({ diff --git a/src/features/defi/providers/cosmos/components/CosmosManager/Overview/CosmosOverview.tsx b/src/features/defi/providers/cosmos/components/CosmosManager/Overview/CosmosOverview.tsx index ed2598cff56..099b0be5e6a 100644 --- a/src/features/defi/providers/cosmos/components/CosmosManager/Overview/CosmosOverview.tsx +++ b/src/features/defi/providers/cosmos/components/CosmosManager/Overview/CosmosOverview.tsx @@ -241,7 +241,7 @@ export const CosmosOverview: React.FC = ({ onAccountIdChange={handleAccountIdChange} positionAddress={accountId ? fromAccountId(accountId).account : undefined} asset={stakingAsset} - name={opportunityData.name!} + name={opportunityData.name} icons={makeOpportunityIcons({ assets, opportunity: opportunityData })} opportunityFiatBalance={fiatAmountAvailable.toFixed(2)} underlyingAssetsCryptoPrecision={underlyingAssetsCryptoPrecision} diff --git a/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Claim/ClaimStatus.tsx b/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Claim/ClaimStatus.tsx index 24413f0f13a..3454bf74c5e 100644 --- a/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Claim/ClaimStatus.tsx +++ b/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Claim/ClaimStatus.tsx @@ -149,6 +149,12 @@ export const ClaimStatus: React.FC = ({ accountId }) => { return confirmedTransaction?.status }, [confirmedTransaction?.status, maybeSafeTx?.isExecutedSafeTx, maybeSafeTx?.isQueuedSafeTx]) + const statusInfo = useMemo(() => { + if (!status) return + + return StatusInfo[status] + }, [status]) + useEffect(() => { if (status && status !== TxStatus.Pending) { const usedGasFeeCryptoPrecision = (() => { @@ -232,8 +238,8 @@ export const ClaimStatus: React.FC = ({ accountId }) => { {status === TxStatus.Pending ? ( ) : ( - - {StatusInfo[status!]?.icon ?? null} + + {statusInfo?.icon ?? null} )} diff --git a/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Deposit/components/Confirm.tsx b/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Deposit/components/Confirm.tsx index 81cc35c50a9..bde2b96f9b0 100644 --- a/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Deposit/components/Confirm.tsx +++ b/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Deposit/components/Confirm.tsx @@ -201,7 +201,7 @@ export const Confirm: React.FC = ({ accountId }) => { = ({ selectHighestStakingBalanceAccountIdByStakingId(state, highestBalanceAccountIdFilter), ) - const opportunityDataFilter = useMemo( - () => ({ + const opportunityDataFilter = useMemo(() => { + const _accountId = accountId ?? highestBalanceAccountId + if (!_accountId) return + + return { userStakingId: serializeUserStakingId( - (accountId ?? highestBalanceAccountId)!, + _accountId, toOpportunityId({ chainId, assetNamespace, assetReference: contractAddress, }), ), - }), - [accountId, assetNamespace, chainId, contractAddress, highestBalanceAccountId], - ) + } + }, [accountId, assetNamespace, chainId, contractAddress, highestBalanceAccountId]) const opportunityData = useAppSelector(state => - selectUserStakingOpportunityByUserStakingId(state, opportunityDataFilter), + opportunityDataFilter + ? selectUserStakingOpportunityByUserStakingId(state, opportunityDataFilter) + : undefined, ) const underlyingAssetsIcons: string[] = useMemo( @@ -125,7 +129,9 @@ export const FoxFarmingOverview: React.FC = ({ ]) const underlyingAssetsWithBalancesAndIcons = useAppSelector(state => - selectUnderlyingStakingAssetsWithBalancesAndIcons(state, opportunityDataFilter), + opportunityDataFilter + ? selectUnderlyingStakingAssetsWithBalancesAndIcons(state, opportunityDataFilter) + : undefined, ) const lpAssetWithBalancesAndIcons = useMemo( diff --git a/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Withdraw/FoxFarmingWithdraw.tsx b/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Withdraw/FoxFarmingWithdraw.tsx index b5daa3b969e..dfdea52f6fe 100644 --- a/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Withdraw/FoxFarmingWithdraw.tsx +++ b/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Withdraw/FoxFarmingWithdraw.tsx @@ -43,21 +43,23 @@ export const FoxFarmingWithdraw: React.FC = ({ const { query, history, location } = useBrowserRouter() const { assetNamespace, chainId, contractAddress } = query - const opportunityDataFilter = useMemo( - () => ({ + const opportunityDataFilter = useMemo(() => { + if (!accountId) return + return { userStakingId: serializeUserStakingId( - accountId!, + accountId, toOpportunityId({ chainId, assetNamespace, assetReference: contractAddress, }), ), - }), - [accountId, assetNamespace, chainId, contractAddress], - ) + } + }, [accountId, assetNamespace, chainId, contractAddress]) const foxFarmingOpportunity = useAppSelector(state => - selectEarnUserStakingOpportunityByUserStakingId(state, opportunityDataFilter), + opportunityDataFilter + ? selectEarnUserStakingOpportunityByUserStakingId(state, opportunityDataFilter) + : undefined, ) const loading = useSelector(selectIsPortfolioLoading) diff --git a/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Withdraw/components/Confirm.tsx b/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Withdraw/components/Confirm.tsx index 3d419489f76..07563b49730 100644 --- a/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Withdraw/components/Confirm.tsx +++ b/src/features/defi/providers/fox-farming/components/FoxFarmingManager/Withdraw/components/Confirm.tsx @@ -178,7 +178,7 @@ export const Confirm: React.FC = ({ accountId, onNext }) => { = ({ accountId }) => { { - if (!network) throw new Error(`Unsupported chainId: ${chainIds![i]}`) + if (!network) throw new Error(`Unsupported chainId: ${chainIds?.[i]}`) }) } diff --git a/src/lib/utils/thorchain/hooks/useThorchainFromAddress.tsx b/src/lib/utils/thorchain/hooks/useThorchainFromAddress.tsx index 28f3ce851a4..f5ad9708998 100644 --- a/src/lib/utils/thorchain/hooks/useThorchainFromAddress.tsx +++ b/src/lib/utils/thorchain/hooks/useThorchainFromAddress.tsx @@ -1,11 +1,11 @@ import type { AccountId, AssetId } from '@shapeshiftoss/caip' import type { HDWallet } from '@shapeshiftoss/hdwallet-core' import type { AccountMetadata } from '@shapeshiftoss/types' -import { useQuery } from '@tanstack/react-query' -import { reactQueries } from 'react-queries' +import { skipToken, useQuery } from '@tanstack/react-query' import type { getThorchainLpPosition } from 'pages/ThorChainLP/queries/queries' import type { getThorchainSaversPosition } from 'state/slices/opportunitiesSlice/resolvers/thorchainsavers/utils' +import { getThorchainFromAddress } from '..' import type { getThorchainLendingPosition } from '../lending' type UseThorchainFromAddressArgs = { @@ -33,18 +33,22 @@ export const useThorchainFromAddress = ({ enabled = true, }: UseThorchainFromAddressArgs) => { const query = useQuery({ - ...reactQueries.common.thorchainFromAddress({ - accountId: accountId!, - assetId: assetId!, - opportunityId, - wallet: wallet!, - accountMetadata: accountMetadata!, - getPosition, - }), + queryKey: ['thorchainFromAddress', accountId, assetId, opportunityId], + queryFn: + accountId && wallet && accountMetadata && assetId && enabled + ? () => + getThorchainFromAddress({ + accountId, + assetId, + opportunityId, + getPosition, + accountMetadata, + wallet, + }) + : skipToken, staleTime: 0, gcTime: 0, select, - enabled: Boolean(enabled && wallet && accountId && accountMetadata && assetId), }) return query diff --git a/src/lib/utils/thorchain/index.ts b/src/lib/utils/thorchain/index.ts index 24d3a4b1d96..48eaa4e0420 100644 --- a/src/lib/utils/thorchain/index.ts +++ b/src/lib/utils/thorchain/index.ts @@ -181,10 +181,15 @@ export const getThorchainFromAddress = async ({ })() return chainId === bchChainId ? `bitcoincash:${address}` : address } catch { - const accountType = accountMetadata?.accountType - const bip44Params = accountMetadata?.bip44Params + // Re-throw if no meta, we obviously can't get an address without it + if (!accountMetadata) throw new Error('No account metadata found') + const accountType = accountMetadata.accountType + const bip44Params = accountMetadata.bip44Params - const chainAdapter = getChainAdapterManager().get(chainId)! + const chainAdapter = getChainAdapterManager().get(chainId) + + // And re-throw if no adapter found. "Shouldn't happen but" yadi yadi yada you know the drill + if (!chainAdapter) throw new Error(`No chain adapter found for chainId: ${chainId}`) const firstReceiveAddress = await chainAdapter.getAddress({ wallet, diff --git a/src/pages/ThorChainLP/components/AddLiquidity/AddLiquidity.tsx b/src/pages/ThorChainLP/components/AddLiquidity/AddLiquidity.tsx index 9b70ee8cc84..9a90d14fb2d 100644 --- a/src/pages/ThorChainLP/components/AddLiquidity/AddLiquidity.tsx +++ b/src/pages/ThorChainLP/components/AddLiquidity/AddLiquidity.tsx @@ -140,6 +140,7 @@ export const AddLiquidityRoutes: React.FC = ({ const renderAddLiquiditySweep = useCallback(() => { if (!confirmedQuote) return null + if (!mixpanel) return const handleSweepSeen = () => { if (confirmedQuote.positionStatus?.incomplete) { @@ -148,7 +149,7 @@ export const AddLiquidityRoutes: React.FC = ({ } history.push(AddLiquidityRoutePaths.Confirm) - mixpanel?.track(MixPanelEvent.LpDepositPreview, confirmedQuote!) + mixpanel.track(MixPanelEvent.LpDepositPreview, confirmedQuote) } return ( diff --git a/src/pages/ThorChainLP/components/AddLiquidity/AddLiquidityInput.tsx b/src/pages/ThorChainLP/components/AddLiquidity/AddLiquidityInput.tsx index 1a1256ad8bf..73bc0337142 100644 --- a/src/pages/ThorChainLP/components/AddLiquidity/AddLiquidityInput.tsx +++ b/src/pages/ThorChainLP/components/AddLiquidity/AddLiquidityInput.tsx @@ -716,7 +716,7 @@ export const AddLiquidityInput: React.FC = ({ // If the asset is not a token, assume it's a native asset and fees are taken from the same asset balance if (!isToken(poolAsset.assetId)) { const assetAmountCryptoBaseUnit = toBaseUnit( - actualAssetDepositAmountCryptoPrecision!, + actualAssetDepositAmountCryptoPrecision, poolAsset?.precision, ) return bnOrZero(assetAmountCryptoBaseUnit) @@ -833,7 +833,7 @@ export const AddLiquidityInput: React.FC = ({ if (!runeTxFeeCryptoBaseUnit) return false const runeAmountCryptoBaseUnit = toBaseUnit( - actualRuneDepositAmountCryptoPrecision!, + actualRuneDepositAmountCryptoPrecision, runeAsset?.precision, ) @@ -885,15 +885,17 @@ export const AddLiquidityInput: React.FC = ({ const handleApprove = useCallback(() => mutate(undefined), [mutate]) const handleSubmit = useCallback(() => { + if (!mixpanel) return + if (!confirmedQuote) return if (isApprovalRequired) return handleApprove() if (isSweepNeeded) return history.push(AddLiquidityRoutePaths.Sweep) if (Boolean(incompleteSide)) { history.push(AddLiquidityRoutePaths.Status) - mixpanel?.track(MixPanelEvent.LpIncompleteDepositConfirm, confirmedQuote!) + mixpanel.track(MixPanelEvent.LpIncompleteDepositConfirm, confirmedQuote) } else { history.push(AddLiquidityRoutePaths.Confirm) - mixpanel?.track(MixPanelEvent.LpDepositPreview, confirmedQuote!) + mixpanel.track(MixPanelEvent.LpDepositPreview, confirmedQuote) } }, [ confirmedQuote, diff --git a/src/pages/ThorChainLP/components/RemoveLiquidity/RemoveLiquidity.tsx b/src/pages/ThorChainLP/components/RemoveLiquidity/RemoveLiquidity.tsx index 3dfcb7da41e..0052f9a393c 100644 --- a/src/pages/ThorChainLP/components/RemoveLiquidity/RemoveLiquidity.tsx +++ b/src/pages/ThorChainLP/components/RemoveLiquidity/RemoveLiquidity.tsx @@ -118,13 +118,14 @@ const RemoveLiquidityRoutes: React.FC = ({ ) const renderRemoveLiquiditySweep = useCallback(() => { + if (!mixpanel) return null if (!confirmedQuote) return null const handleSweepSeen = () => { if (confirmedQuote.positionStatus?.incomplete) { - mixpanel?.track(MixPanelEvent.LpIncompleteWithdrawPreview, confirmedQuote!) + mixpanel.track(MixPanelEvent.LpIncompleteWithdrawPreview, confirmedQuote) } else { - mixpanel?.track(MixPanelEvent.LpWithdrawPreview, confirmedQuote!) + mixpanel.track(MixPanelEvent.LpWithdrawPreview, confirmedQuote) } history.push(RemoveLiquidityRoutePaths.Confirm) diff --git a/src/pages/ThorChainLP/components/RemoveLiquidity/RemoveLiquidityInput.tsx b/src/pages/ThorChainLP/components/RemoveLiquidity/RemoveLiquidityInput.tsx index 6dc465a6f2b..afe92847199 100644 --- a/src/pages/ThorChainLP/components/RemoveLiquidity/RemoveLiquidityInput.tsx +++ b/src/pages/ThorChainLP/components/RemoveLiquidity/RemoveLiquidityInput.tsx @@ -25,12 +25,11 @@ import { thorchainAssetId, thorchainChainId, toAccountId } from '@shapeshiftoss/ import { SwapperName } from '@shapeshiftoss/swapper' import type { Asset, MarketData } from '@shapeshiftoss/types' import { convertPercentageToBasisPoints } from '@shapeshiftoss/utils' -import { useQuery } from '@tanstack/react-query' +import { skipToken, useQuery } from '@tanstack/react-query' import React, { useCallback, useEffect, useMemo, useState } from 'react' import { BiSolidBoltCircle } from 'react-icons/bi' import { FaPlus } from 'react-icons/fa6' import { useTranslate } from 'react-polyglot' -import { reactQueries } from 'react-queries' import { useIsTradingActive } from 'react-queries/hooks/useIsTradingActive' import { useHistory } from 'react-router' import { Amount } from 'components/Amount/Amount' @@ -48,7 +47,7 @@ import { fromBaseUnit, toBaseUnit } from 'lib/math' import { getMixPanel } from 'lib/mixpanel/mixPanelSingleton' import { MixPanelEvent } from 'lib/mixpanel/types' import { assertUnreachable } from 'lib/utils' -import { fromThorBaseUnit } from 'lib/utils/thorchain' +import { fromThorBaseUnit, getThorchainFromAddress } from 'lib/utils/thorchain' import { THOR_PRECISION } from 'lib/utils/thorchain/constants' import { useSendThorTx } from 'lib/utils/thorchain/hooks/useSendThorTx' import { estimateRemoveThorchainLiquidityPosition } from 'lib/utils/thorchain/lp' @@ -398,15 +397,19 @@ export const RemoveLiquidityInput: React.FC = ({ ) const { data: poolAssetAccountAddress } = useQuery({ - ...reactQueries.common.thorchainFromAddress({ - accountId, - assetId: poolAsset?.assetId!, - opportunityId, - wallet: wallet!, - accountMetadata: poolAssetAccountMetadata!, - getPosition: getThorchainLpPosition, - }), - enabled: Boolean(poolAsset?.assetId && wallet && poolAssetAccountMetadata), + queryKey: ['thorchainFromAddress', accountId, poolAsset?.assetId, opportunityId], + queryFn: + wallet && accountId && poolAssetAccountMetadata && poolAsset + ? () => + getThorchainFromAddress({ + accountId, + assetId: poolAsset.assetId, + opportunityId, + getPosition: getThorchainLpPosition, + accountMetadata: poolAssetAccountMetadata, + wallet, + }) + : skipToken, }) const { @@ -723,12 +726,14 @@ export const RemoveLiquidityInput: React.FC = ({ useIsSweepNeededQuery(isSweepNeededArgs) const handleSubmit = useCallback(() => { + if (!mixpanel) return + if (!confirmedQuote) return if (isSweepNeeded) return history.push(RemoveLiquidityRoutePaths.Sweep) if (incompleteSide) { - mixpanel?.track(MixPanelEvent.LpIncompleteWithdrawPreview, confirmedQuote!) + mixpanel.track(MixPanelEvent.LpIncompleteWithdrawPreview, confirmedQuote) } else { - mixpanel?.track(MixPanelEvent.LpWithdrawPreview, confirmedQuote!) + mixpanel.track(MixPanelEvent.LpWithdrawPreview, confirmedQuote) } history.push(RemoveLiquidityRoutePaths.Confirm) diff --git a/src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx b/src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx index d566a501292..0a782fef0f1 100644 --- a/src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx +++ b/src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx @@ -32,7 +32,7 @@ import { fromBaseUnit, toBaseUnit } from 'lib/math' import { getMixPanel } from 'lib/mixpanel/mixPanelSingleton' import { MixPanelEvent } from 'lib/mixpanel/types' import { sleep } from 'lib/poll/poll' -import { waitForThorchainUpdate } from 'lib/utils/thorchain' +import { getThorchainFromAddress, waitForThorchainUpdate } from 'lib/utils/thorchain' import { THORCHAIN_AFFILIATE_NAME } from 'lib/utils/thorchain/constants' import { useSendThorTx } from 'lib/utils/thorchain/hooks/useSendThorTx' import { useThorchainFromAddress } from 'lib/utils/thorchain/hooks/useThorchainFromAddress' @@ -128,21 +128,25 @@ export const TransactionRow: React.FC = ({ return isRuneTx ? runeAccountMetadata : poolAssetAccountMetadata }, [isRuneTx, runeAccountMetadata, poolAssetAccountMetadata]) - const { queryKey: thorchainFromAddressQueryKey, queryFn: thorchainFromAddressQueryFn } = - reactQueries.common.thorchainFromAddress({ - accountId: fromAccountId!, - assetId: isRuneTx ? thorchainAssetId : poolAssetId, - opportunityId: confirmedQuote.opportunityId, - wallet: wallet!, - accountMetadata: fromAccountMetadata!, - getPosition: getThorchainLpPosition, - }) - const { data: fromAddress } = useQuery({ - queryKey: thorchainFromAddressQueryKey, - queryFn: Boolean(fromAccountId && fromAccountMetadata && wallet) - ? thorchainFromAddressQueryFn - : skipToken, + queryKey: [ + 'thorchainFromAddress', + fromAccountId, + isRuneTx ? thorchainAssetId : poolAssetId, + confirmedQuote.opportunityId, + ], + queryFn: + fromAccountId && wallet && fromAccountId && fromAccountMetadata + ? () => + getThorchainFromAddress({ + accountId: fromAccountId, + assetId: isRuneTx ? thorchainAssetId : poolAssetId, + opportunityId: confirmedQuote.opportunityId, + getPosition: getThorchainLpPosition, + accountMetadata: fromAccountMetadata, + wallet, + }) + : skipToken, }) const pairAssetAccountId = useMemo(() => { diff --git a/src/state/slices/opportunitiesSlice/resolvers/uniV2/index.ts b/src/state/slices/opportunitiesSlice/resolvers/uniV2/index.ts index 2b0d136a7d0..2d3b2cc8f8e 100644 --- a/src/state/slices/opportunitiesSlice/resolvers/uniV2/index.ts +++ b/src/state/slices/opportunitiesSlice/resolvers/uniV2/index.ts @@ -224,7 +224,7 @@ export const uniV2LpOpportunitiesMetadataResolver = async ({ ) const totalLiquidityFiat = portalsAppBalanceData - ? bnOrZero(portalsAppBalanceData.dataProps?.liquidity!) + ? bnOrZero(portalsAppBalanceData.dataProps?.liquidity) : token0ReservesCryptoPrecision.times(token0Price).times(2) const tvl = totalLiquidityFiat.toString() const price = bnOrZero(tvl) From b933520e2c59cd520b87d5e56deea0ce54e53b1f Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 21 Feb 2025 12:33:42 +0100 Subject: [PATCH 05/13] feat: revert lint rule for the time being --- .eslintrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.eslintrc b/.eslintrc index b591c375e56..5046fae8852 100644 --- a/.eslintrc +++ b/.eslintrc @@ -97,8 +97,8 @@ "react/jsx-handler-names": "error", "require-await": "error", "import/no-duplicates": "error", - "react-memo/require-usememo": "error", - "@typescript-eslint/no-non-null-assertion": "warn" + "react-memo/require-usememo": "error" + // "@typescript-eslint/no-non-null-assertion": "warn" }, "overrides": [ { From f762807d24dabe7206f87b860f1536fbf2df6602 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 21 Feb 2025 12:56:34 +0100 Subject: [PATCH 06/13] fix: ci --- src/features/defi/components/Deposit/Deposit.tsx | 6 +++++- .../defi/components/PairIcons/PairIcons.tsx | 14 +++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/features/defi/components/Deposit/Deposit.tsx b/src/features/defi/components/Deposit/Deposit.tsx index 234d1be2714..9879adcd2e2 100644 --- a/src/features/defi/components/Deposit/Deposit.tsx +++ b/src/features/defi/components/Deposit/Deposit.tsx @@ -106,7 +106,11 @@ export const Deposit = ({ }, }) - const handleMaxClick = useCallback(() => onMaxClick?.(setValue), [onMaxClick, setValue]) + const handleMaxClick = useCallback(() => { + if (!onMaxClick) return Promise.resolve() + + return onMaxClick(setValue) + }, [onMaxClick, setValue]) const values = useWatch({ control }) const { field: cryptoAmount } = useController({ diff --git a/src/features/defi/components/PairIcons/PairIcons.tsx b/src/features/defi/components/PairIcons/PairIcons.tsx index 0b1486ad6bd..caec0debe0e 100644 --- a/src/features/defi/components/PairIcons/PairIcons.tsx +++ b/src/features/defi/components/PairIcons/PairIcons.tsx @@ -32,14 +32,20 @@ export const PairIcons = ({ showFirst, ...styleProps }: { - icons: string[] + icons: string[] | undefined iconBoxSize?: AvatarProps['boxSize'] iconSize?: AvatarProps['size'] showFirst?: boolean -} & FlexProps): JSX.Element => { - const firstIcon = icons[0] +} & FlexProps): JSX.Element | null => { + const firstIcon = useMemo(() => { + if (!icons?.length) return + + return icons[0] + }, [icons]) const remainingIcons = useMemo(() => { + if (!icons?.length) return + const iconsMinusFirst = icons.slice(showFirst ? 1 : 0) if (iconsMinusFirst.length > 1) { return ( @@ -94,6 +100,8 @@ export const PairIcons = ({ )) }, [iconBoxSize, iconSize, icons, showFirst]) + if (!icons?.length) return null + return ( {showFirst && } From c7b8dd90d7aa76b5a2d25d33af5871074133d49d Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 21 Feb 2025 13:22:55 +0100 Subject: [PATCH 07/13] feat: don't non-null assert CSPs --- .eslintrc | 4 ++-- .../headers/csps/chains/arbitrum.ts | 17 ++++++++++---- .../headers/csps/chains/arbitrumNova.ts | 19 +++++++++++++--- .../headers/csps/chains/avalanche.ts | 16 +++++++++++--- react-app-rewired/headers/csps/chains/base.ts | 15 ++++++++++--- .../headers/csps/chains/bitcoin.ts | 13 +++++++---- .../headers/csps/chains/bitcoincash.ts | 14 ++++++++---- .../headers/csps/chains/bnbsmartchain.ts | 19 +++++++++++++--- .../headers/csps/chains/cosmos.ts | 13 +++++++---- .../headers/csps/chains/dogecoin.ts | 13 +++++++---- .../headers/csps/chains/ethereum.ts | 20 +++++++++++++---- .../headers/csps/chains/gnosis.ts | 17 ++++++++++---- .../headers/csps/chains/litecoin.ts | 13 +++++++---- .../headers/csps/chains/optimism.ts | 17 ++++++++++---- .../headers/csps/chains/polygon.ts | 17 ++++++++++---- .../headers/csps/chains/solana.ts | 16 +++++++++++--- .../headers/csps/chains/thorchain.ts | 22 +++++++++++++++---- react-app-rewired/headers/csps/chatwoot.ts | 10 ++++++--- .../headers/csps/defi/mtpelerin.ts | 14 +++++++++--- .../headers/csps/fiatRamps/onRamper.ts | 12 ++++++---- .../headers/csps/plugins/foxPage.ts | 18 +++++++++++---- .../headers/csps/wallets/keepkey.ts | 11 ++++++---- .../headers/csps/wallets/walletConnect.ts | 7 +++++- .../headers/csps/wallets/walletMigration.ts | 2 +- react-app-rewired/headers/types.ts | 5 +++-- react-app-rewired/headers/util.ts | 7 +++++- 26 files changed, 267 insertions(+), 84 deletions(-) diff --git a/.eslintrc b/.eslintrc index 5046fae8852..b591c375e56 100644 --- a/.eslintrc +++ b/.eslintrc @@ -97,8 +97,8 @@ "react/jsx-handler-names": "error", "require-await": "error", "import/no-duplicates": "error", - "react-memo/require-usememo": "error" - // "@typescript-eslint/no-non-null-assertion": "warn" + "react-memo/require-usememo": "error", + "@typescript-eslint/no-non-null-assertion": "warn" }, "overrides": [ { diff --git a/react-app-rewired/headers/csps/chains/arbitrum.ts b/react-app-rewired/headers/csps/chains/arbitrum.ts index be74a30323e..c0d768c242f 100644 --- a/react-app-rewired/headers/csps/chains/arbitrum.ts +++ b/react-app-rewired/headers/csps/chains/arbitrum.ts @@ -1,10 +1,19 @@ import type { Csp } from '../../types' +const REACT_APP_ARBITRUM_NODE_URL = process.env.REACT_APP_ARBITRUM_NODE_URL +const REACT_APP_UNCHAINED_ARBITRUM_HTTP_URL = process.env.REACT_APP_UNCHAINED_ARBITRUM_HTTP_URL +const REACT_APP_UNCHAINED_ARBITRUM_WS_URL = process.env.REACT_APP_UNCHAINED_ARBITRUM_WS_URL + +if (!REACT_APP_ARBITRUM_NODE_URL) throw new Error('REACT_APP_ARBITRUM_NODE_URL is required') +if (!REACT_APP_UNCHAINED_ARBITRUM_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_ARBITRUM_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_ARBITRUM_WS_URL) + throw new Error('REACT_APP_UNCHAINED_ARBITRUM_WS_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_ARBITRUM_NODE_URL!, - process.env.REACT_APP_UNCHAINED_ARBITRUM_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_ARBITRUM_WS_URL!, - 'https://arbitrum.llamarpc.com', + REACT_APP_ARBITRUM_NODE_URL, + REACT_APP_UNCHAINED_ARBITRUM_HTTP_URL, + REACT_APP_UNCHAINED_ARBITRUM_WS_URL, ], } diff --git a/react-app-rewired/headers/csps/chains/arbitrumNova.ts b/react-app-rewired/headers/csps/chains/arbitrumNova.ts index 4234293823c..c93dd5d9b89 100644 --- a/react-app-rewired/headers/csps/chains/arbitrumNova.ts +++ b/react-app-rewired/headers/csps/chains/arbitrumNova.ts @@ -1,10 +1,23 @@ import type { Csp } from '../../types' +const REACT_APP_ARBITRUM_NOVA_NODE_URL = process.env.REACT_APP_ARBITRUM_NOVA_NODE_URL +const REACT_APP_UNCHAINED_ARBITRUM_NOVA_HTTP_URL = + process.env.REACT_APP_UNCHAINED_ARBITRUM_NOVA_HTTP_URL +const REACT_APP_UNCHAINED_ARBITRUM_NOVA_WS_URL = + process.env.REACT_APP_UNCHAINED_ARBITRUM_NOVA_WS_URL + +if (!REACT_APP_ARBITRUM_NOVA_NODE_URL) + throw new Error('REACT_APP_ARBITRUM_NOVA_NODE_URL is required') +if (!REACT_APP_UNCHAINED_ARBITRUM_NOVA_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_ARBITRUM_NOVA_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_ARBITRUM_NOVA_WS_URL) + throw new Error('REACT_APP_UNCHAINED_ARBITRUM_NOVA_WS_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_ARBITRUM_NOVA_NODE_URL!, - process.env.REACT_APP_UNCHAINED_ARBITRUM_NOVA_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_ARBITRUM_NOVA_WS_URL!, + REACT_APP_ARBITRUM_NOVA_NODE_URL, + REACT_APP_UNCHAINED_ARBITRUM_NOVA_HTTP_URL, + REACT_APP_UNCHAINED_ARBITRUM_NOVA_WS_URL, 'https://nova.arbitrum.io/rpc', ], } diff --git a/react-app-rewired/headers/csps/chains/avalanche.ts b/react-app-rewired/headers/csps/chains/avalanche.ts index 76c54d8792d..a488e979fc9 100644 --- a/react-app-rewired/headers/csps/chains/avalanche.ts +++ b/react-app-rewired/headers/csps/chains/avalanche.ts @@ -1,10 +1,20 @@ import type { Csp } from '../../types' +const REACT_APP_AVALANCHE_NODE_URL = process.env.REACT_APP_AVALANCHE_NODE_URL +const REACT_APP_UNCHAINED_AVALANCHE_HTTP_URL = process.env.REACT_APP_UNCHAINED_AVALANCHE_HTTP_URL +const REACT_APP_UNCHAINED_AVALANCHE_WS_URL = process.env.REACT_APP_UNCHAINED_AVALANCHE_WS_URL + +if (!REACT_APP_AVALANCHE_NODE_URL) throw new Error('REACT_APP_AVALANCHE_NODE_URL is required') +if (!REACT_APP_UNCHAINED_AVALANCHE_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_AVALANCHE_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_AVALANCHE_WS_URL) + throw new Error('REACT_APP_UNCHAINED_AVALANCHE_WS_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_AVALANCHE_NODE_URL!, - process.env.REACT_APP_UNCHAINED_AVALANCHE_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_AVALANCHE_WS_URL!, + REACT_APP_AVALANCHE_NODE_URL, + REACT_APP_UNCHAINED_AVALANCHE_HTTP_URL, + REACT_APP_UNCHAINED_AVALANCHE_WS_URL, 'https://api.avax.network/ext/bc/C/rpc', ], } diff --git a/react-app-rewired/headers/csps/chains/base.ts b/react-app-rewired/headers/csps/chains/base.ts index 0ca2059532b..ffa2ddab8b5 100644 --- a/react-app-rewired/headers/csps/chains/base.ts +++ b/react-app-rewired/headers/csps/chains/base.ts @@ -1,10 +1,19 @@ import type { Csp } from '../../types' +const REACT_APP_BASE_NODE_URL = process.env.REACT_APP_BASE_NODE_URL +const REACT_APP_UNCHAINED_BASE_HTTP_URL = process.env.REACT_APP_UNCHAINED_BASE_HTTP_URL +const REACT_APP_UNCHAINED_BASE_WS_URL = process.env.REACT_APP_UNCHAINED_BASE_WS_URL + +if (!REACT_APP_BASE_NODE_URL) throw new Error('REACT_APP_BASE_NODE_URL is required') +if (!REACT_APP_UNCHAINED_BASE_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_BASE_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_BASE_WS_URL) throw new Error('REACT_APP_UNCHAINED_BASE_WS_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_BASE_NODE_URL!, - process.env.REACT_APP_UNCHAINED_BASE_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_BASE_WS_URL!, + REACT_APP_BASE_NODE_URL, + REACT_APP_UNCHAINED_BASE_HTTP_URL, + REACT_APP_UNCHAINED_BASE_WS_URL, 'https://base.llamarpc.com', ], } diff --git a/react-app-rewired/headers/csps/chains/bitcoin.ts b/react-app-rewired/headers/csps/chains/bitcoin.ts index 089b119330c..3f8515600f2 100644 --- a/react-app-rewired/headers/csps/chains/bitcoin.ts +++ b/react-app-rewired/headers/csps/chains/bitcoin.ts @@ -1,8 +1,13 @@ import type { Csp } from '../../types' +const REACT_APP_UNCHAINED_BITCOIN_HTTP_URL = process.env.REACT_APP_UNCHAINED_BITCOIN_HTTP_URL +const REACT_APP_UNCHAINED_BITCOIN_WS_URL = process.env.REACT_APP_UNCHAINED_BITCOIN_WS_URL + +if (!REACT_APP_UNCHAINED_BITCOIN_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_BITCOIN_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_BITCOIN_WS_URL) + throw new Error('REACT_APP_UNCHAINED_BITCOIN_WS_URL is required') + export const csp: Csp = { - 'connect-src': [ - process.env.REACT_APP_UNCHAINED_BITCOIN_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_BITCOIN_WS_URL!, - ], + 'connect-src': [REACT_APP_UNCHAINED_BITCOIN_HTTP_URL, REACT_APP_UNCHAINED_BITCOIN_WS_URL], } diff --git a/react-app-rewired/headers/csps/chains/bitcoincash.ts b/react-app-rewired/headers/csps/chains/bitcoincash.ts index dcfb8b2dc14..0259aaa6026 100644 --- a/react-app-rewired/headers/csps/chains/bitcoincash.ts +++ b/react-app-rewired/headers/csps/chains/bitcoincash.ts @@ -1,8 +1,14 @@ import type { Csp } from '../../types' +const REACT_APP_UNCHAINED_BITCOINCASH_HTTP_URL = + process.env.REACT_APP_UNCHAINED_BITCOINCASH_HTTP_URL +const REACT_APP_UNCHAINED_BITCOINCASH_WS_URL = process.env.REACT_APP_UNCHAINED_BITCOINCASH_WS_URL + +if (!REACT_APP_UNCHAINED_BITCOINCASH_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_BITCOINCASH_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_BITCOINCASH_WS_URL) + throw new Error('REACT_APP_UNCHAINED_BITCOINCASH_WS_URL is required') + export const csp: Csp = { - 'connect-src': [ - process.env.REACT_APP_UNCHAINED_BITCOINCASH_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_BITCOINCASH_WS_URL!, - ], + 'connect-src': [REACT_APP_UNCHAINED_BITCOINCASH_HTTP_URL, REACT_APP_UNCHAINED_BITCOINCASH_WS_URL], } diff --git a/react-app-rewired/headers/csps/chains/bnbsmartchain.ts b/react-app-rewired/headers/csps/chains/bnbsmartchain.ts index 885faded368..dd325d3ea53 100644 --- a/react-app-rewired/headers/csps/chains/bnbsmartchain.ts +++ b/react-app-rewired/headers/csps/chains/bnbsmartchain.ts @@ -1,10 +1,23 @@ import type { Csp } from '../../types' +const REACT_APP_BNBSMARTCHAIN_NODE_URL = process.env.REACT_APP_BNBSMARTCHAIN_NODE_URL +const REACT_APP_UNCHAINED_BNBSMARTCHAIN_HTTP_URL = + process.env.REACT_APP_UNCHAINED_BNBSMARTCHAIN_HTTP_URL +const REACT_APP_UNCHAINED_BNBSMARTCHAIN_WS_URL = + process.env.REACT_APP_UNCHAINED_BNBSMARTCHAIN_WS_URL + +if (!REACT_APP_BNBSMARTCHAIN_NODE_URL) + throw new Error('REACT_APP_BNBSMARTCHAIN_NODE_URL is required') +if (!REACT_APP_UNCHAINED_BNBSMARTCHAIN_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_BNBSMARTCHAIN_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_BNBSMARTCHAIN_WS_URL) + throw new Error('REACT_APP_UNCHAINED_BNBSMARTCHAIN_WS_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_BNBSMARTCHAIN_NODE_URL!, - process.env.REACT_APP_UNCHAINED_BNBSMARTCHAIN_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_BNBSMARTCHAIN_WS_URL!, + REACT_APP_BNBSMARTCHAIN_NODE_URL, + REACT_APP_UNCHAINED_BNBSMARTCHAIN_HTTP_URL, + REACT_APP_UNCHAINED_BNBSMARTCHAIN_WS_URL, 'https://binance.llamarpc.com', ], } diff --git a/react-app-rewired/headers/csps/chains/cosmos.ts b/react-app-rewired/headers/csps/chains/cosmos.ts index 5055f34d84d..79b12e5521a 100644 --- a/react-app-rewired/headers/csps/chains/cosmos.ts +++ b/react-app-rewired/headers/csps/chains/cosmos.ts @@ -1,10 +1,15 @@ import type { Csp } from '../../types' +const REACT_APP_UNCHAINED_COSMOS_HTTP_URL = process.env.REACT_APP_UNCHAINED_COSMOS_HTTP_URL +const REACT_APP_UNCHAINED_COSMOS_WS_URL = process.env.REACT_APP_UNCHAINED_COSMOS_WS_URL + +if (!REACT_APP_UNCHAINED_COSMOS_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_COSMOS_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_COSMOS_WS_URL) + throw new Error('REACT_APP_UNCHAINED_COSMOS_WS_URL is required') + export const csp: Csp = { - 'connect-src': [ - process.env.REACT_APP_UNCHAINED_COSMOS_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_COSMOS_WS_URL!, - ], + 'connect-src': [REACT_APP_UNCHAINED_COSMOS_HTTP_URL, REACT_APP_UNCHAINED_COSMOS_WS_URL], 'img-src': [ 'https://raw.githubusercontent.com/cosmostation/', 'https://raw.githubusercontent.com/cosmos/chain-registry/', diff --git a/react-app-rewired/headers/csps/chains/dogecoin.ts b/react-app-rewired/headers/csps/chains/dogecoin.ts index cef35324b72..a22dce0e3d8 100644 --- a/react-app-rewired/headers/csps/chains/dogecoin.ts +++ b/react-app-rewired/headers/csps/chains/dogecoin.ts @@ -1,8 +1,13 @@ import type { Csp } from '../../types' +const REACT_APP_UNCHAINED_DOGECOIN_HTTP_URL = process.env.REACT_APP_UNCHAINED_DOGECOIN_HTTP_URL +const REACT_APP_UNCHAINED_DOGECOIN_WS_URL = process.env.REACT_APP_UNCHAINED_DOGECOIN_WS_URL + +if (!REACT_APP_UNCHAINED_DOGECOIN_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_DOGECOIN_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_DOGECOIN_WS_URL) + throw new Error('REACT_APP_UNCHAINED_DOGECOIN_WS_URL is required') + export const csp: Csp = { - 'connect-src': [ - process.env.REACT_APP_UNCHAINED_DOGECOIN_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_DOGECOIN_WS_URL!, - ], + 'connect-src': [REACT_APP_UNCHAINED_DOGECOIN_HTTP_URL, REACT_APP_UNCHAINED_DOGECOIN_WS_URL], } diff --git a/react-app-rewired/headers/csps/chains/ethereum.ts b/react-app-rewired/headers/csps/chains/ethereum.ts index 60844caa027..45ca95cbe1c 100644 --- a/react-app-rewired/headers/csps/chains/ethereum.ts +++ b/react-app-rewired/headers/csps/chains/ethereum.ts @@ -1,11 +1,23 @@ import type { Csp } from '../../types' +const REACT_APP_ETHEREUM_NODE_URL = process.env.REACT_APP_ETHEREUM_NODE_URL +const REACT_APP_UNCHAINED_ETHEREUM_HTTP_URL = process.env.REACT_APP_UNCHAINED_ETHEREUM_HTTP_URL +const REACT_APP_UNCHAINED_ETHEREUM_WS_URL = process.env.REACT_APP_UNCHAINED_ETHEREUM_WS_URL +const REACT_APP_ALCHEMY_POLYGON_URL = process.env.REACT_APP_ALCHEMY_POLYGON_URL + +if (!REACT_APP_ETHEREUM_NODE_URL) throw new Error('REACT_APP_ETHEREUM_NODE_URL is required') +if (!REACT_APP_UNCHAINED_ETHEREUM_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_ETHEREUM_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_ETHEREUM_WS_URL) + throw new Error('REACT_APP_UNCHAINED_ETHEREUM_WS_URL is required') +if (!REACT_APP_ALCHEMY_POLYGON_URL) throw new Error('REACT_APP_ALCHEMY_POLYGON_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_ETHEREUM_NODE_URL!, - process.env.REACT_APP_UNCHAINED_ETHEREUM_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_ETHEREUM_WS_URL!, - process.env.REACT_APP_ALCHEMY_POLYGON_URL!, + REACT_APP_ETHEREUM_NODE_URL, + REACT_APP_UNCHAINED_ETHEREUM_HTTP_URL, + REACT_APP_UNCHAINED_ETHEREUM_WS_URL, + REACT_APP_ALCHEMY_POLYGON_URL, 'https://eth.llamarpc.com', ], } diff --git a/react-app-rewired/headers/csps/chains/gnosis.ts b/react-app-rewired/headers/csps/chains/gnosis.ts index 915cd400f32..2793ccb8959 100644 --- a/react-app-rewired/headers/csps/chains/gnosis.ts +++ b/react-app-rewired/headers/csps/chains/gnosis.ts @@ -1,10 +1,19 @@ import type { Csp } from '../../types' +const REACT_APP_GNOSIS_NODE_URL = process.env.REACT_APP_GNOSIS_NODE_URL +const REACT_APP_UNCHAINED_GNOSIS_HTTP_URL = process.env.REACT_APP_UNCHAINED_GNOSIS_HTTP_URL +const REACT_APP_UNCHAINED_GNOSIS_WS_URL = process.env.REACT_APP_UNCHAINED_GNOSIS_WS_URL + +if (!REACT_APP_GNOSIS_NODE_URL) throw new Error('REACT_APP_GNOSIS_NODE_URL is required') +if (!REACT_APP_UNCHAINED_GNOSIS_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_GNOSIS_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_GNOSIS_WS_URL) + throw new Error('REACT_APP_UNCHAINED_GNOSIS_WS_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_GNOSIS_NODE_URL!, - process.env.REACT_APP_UNCHAINED_GNOSIS_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_GNOSIS_WS_URL!, - 'https://rpc.gnosischain.com', + REACT_APP_GNOSIS_NODE_URL, + REACT_APP_UNCHAINED_GNOSIS_HTTP_URL, + REACT_APP_UNCHAINED_GNOSIS_WS_URL, ], } diff --git a/react-app-rewired/headers/csps/chains/litecoin.ts b/react-app-rewired/headers/csps/chains/litecoin.ts index 2a9fa23a22d..7c1b2b5574f 100644 --- a/react-app-rewired/headers/csps/chains/litecoin.ts +++ b/react-app-rewired/headers/csps/chains/litecoin.ts @@ -1,8 +1,13 @@ import type { Csp } from '../../types' +const REACT_APP_UNCHAINED_LITECOIN_HTTP_URL = process.env.REACT_APP_UNCHAINED_LITECOIN_HTTP_URL +const REACT_APP_UNCHAINED_LITECOIN_WS_URL = process.env.REACT_APP_UNCHAINED_LITECOIN_WS_URL + +if (!REACT_APP_UNCHAINED_LITECOIN_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_LITECOIN_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_LITECOIN_WS_URL) + throw new Error('REACT_APP_UNCHAINED_LITECOIN_WS_URL is required') + export const csp: Csp = { - 'connect-src': [ - process.env.REACT_APP_UNCHAINED_LITECOIN_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_LITECOIN_WS_URL!, - ], + 'connect-src': [REACT_APP_UNCHAINED_LITECOIN_HTTP_URL, REACT_APP_UNCHAINED_LITECOIN_WS_URL], } diff --git a/react-app-rewired/headers/csps/chains/optimism.ts b/react-app-rewired/headers/csps/chains/optimism.ts index 7e90cbb836c..74e8067a82d 100644 --- a/react-app-rewired/headers/csps/chains/optimism.ts +++ b/react-app-rewired/headers/csps/chains/optimism.ts @@ -1,10 +1,19 @@ import type { Csp } from '../../types' +const REACT_APP_OPTIMISM_NODE_URL = process.env.REACT_APP_OPTIMISM_NODE_URL +const REACT_APP_UNCHAINED_OPTIMISM_HTTP_URL = process.env.REACT_APP_UNCHAINED_OPTIMISM_HTTP_URL +const REACT_APP_UNCHAINED_OPTIMISM_WS_URL = process.env.REACT_APP_UNCHAINED_OPTIMISM_WS_URL + +if (!REACT_APP_OPTIMISM_NODE_URL) throw new Error('REACT_APP_OPTIMISM_NODE_URL is required') +if (!REACT_APP_UNCHAINED_OPTIMISM_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_OPTIMISM_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_OPTIMISM_WS_URL) + throw new Error('REACT_APP_UNCHAINED_OPTIMISM_WS_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_OPTIMISM_NODE_URL!, - process.env.REACT_APP_UNCHAINED_OPTIMISM_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_OPTIMISM_WS_URL!, - 'https://optimism.llamarpc.com', + REACT_APP_OPTIMISM_NODE_URL, + REACT_APP_UNCHAINED_OPTIMISM_HTTP_URL, + REACT_APP_UNCHAINED_OPTIMISM_WS_URL, ], } diff --git a/react-app-rewired/headers/csps/chains/polygon.ts b/react-app-rewired/headers/csps/chains/polygon.ts index 74d7ad3ae48..cd2c8155367 100644 --- a/react-app-rewired/headers/csps/chains/polygon.ts +++ b/react-app-rewired/headers/csps/chains/polygon.ts @@ -1,10 +1,19 @@ import type { Csp } from '../../types' +const REACT_APP_POLYGON_NODE_URL = process.env.REACT_APP_POLYGON_NODE_URL +const REACT_APP_UNCHAINED_POLYGON_HTTP_URL = process.env.REACT_APP_UNCHAINED_POLYGON_HTTP_URL +const REACT_APP_UNCHAINED_POLYGON_WS_URL = process.env.REACT_APP_UNCHAINED_POLYGON_WS_URL + +if (!REACT_APP_POLYGON_NODE_URL) throw new Error('REACT_APP_POLYGON_NODE_URL is required') +if (!REACT_APP_UNCHAINED_POLYGON_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_POLYGON_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_POLYGON_WS_URL) + throw new Error('REACT_APP_UNCHAINED_POLYGON_WS_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_POLYGON_NODE_URL!, - process.env.REACT_APP_UNCHAINED_POLYGON_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_POLYGON_WS_URL!, - 'https://polygon.llamarpc.com', + REACT_APP_POLYGON_NODE_URL, + REACT_APP_UNCHAINED_POLYGON_HTTP_URL, + REACT_APP_UNCHAINED_POLYGON_WS_URL, ], } diff --git a/react-app-rewired/headers/csps/chains/solana.ts b/react-app-rewired/headers/csps/chains/solana.ts index 78d30783a06..74232be56bd 100644 --- a/react-app-rewired/headers/csps/chains/solana.ts +++ b/react-app-rewired/headers/csps/chains/solana.ts @@ -1,9 +1,19 @@ import type { Csp } from '../../types' +const REACT_APP_UNCHAINED_SOLANA_HTTP_URL = process.env.REACT_APP_UNCHAINED_SOLANA_HTTP_URL +const REACT_APP_UNCHAINED_SOLANA_WS_URL = process.env.REACT_APP_UNCHAINED_SOLANA_WS_URL +const REACT_APP_SOLANA_NODE_URL = process.env.REACT_APP_SOLANA_NODE_URL + +if (!REACT_APP_UNCHAINED_SOLANA_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_SOLANA_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_SOLANA_WS_URL) + throw new Error('REACT_APP_UNCHAINED_SOLANA_WS_URL is required') +if (!REACT_APP_SOLANA_NODE_URL) throw new Error('REACT_APP_SOLANA_NODE_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_UNCHAINED_SOLANA_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_SOLANA_WS_URL!, - process.env.REACT_APP_SOLANA_NODE_URL!, + REACT_APP_UNCHAINED_SOLANA_HTTP_URL, + REACT_APP_UNCHAINED_SOLANA_WS_URL, + REACT_APP_SOLANA_NODE_URL, ], } diff --git a/react-app-rewired/headers/csps/chains/thorchain.ts b/react-app-rewired/headers/csps/chains/thorchain.ts index ee6611bcba6..7e7dcaa20dc 100644 --- a/react-app-rewired/headers/csps/chains/thorchain.ts +++ b/react-app-rewired/headers/csps/chains/thorchain.ts @@ -1,10 +1,24 @@ import type { Csp } from '../../types' +const REACT_APP_UNCHAINED_THORCHAIN_HTTP_URL = process.env.REACT_APP_UNCHAINED_THORCHAIN_HTTP_URL +const REACT_APP_UNCHAINED_THORCHAIN_WS_URL = process.env.REACT_APP_UNCHAINED_THORCHAIN_WS_URL +const REACT_APP_UNCHAINED_THORCHAIN_V1_HTTP_URL = + process.env.REACT_APP_UNCHAINED_THORCHAIN_V1_HTTP_URL +const REACT_APP_THORCHAIN_NODE_URL = process.env.REACT_APP_THORCHAIN_NODE_URL + +if (!REACT_APP_UNCHAINED_THORCHAIN_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_THORCHAIN_HTTP_URL is required') +if (!REACT_APP_UNCHAINED_THORCHAIN_WS_URL) + throw new Error('REACT_APP_UNCHAINED_THORCHAIN_WS_URL is required') +if (!REACT_APP_UNCHAINED_THORCHAIN_V1_HTTP_URL) + throw new Error('REACT_APP_UNCHAINED_THORCHAIN_V1_HTTP_URL is required') +if (!REACT_APP_THORCHAIN_NODE_URL) throw new Error('REACT_APP_THORCHAIN_NODE_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_UNCHAINED_THORCHAIN_HTTP_URL!, - process.env.REACT_APP_UNCHAINED_THORCHAIN_WS_URL!, - process.env.REACT_APP_UNCHAINED_THORCHAIN_V1_HTTP_URL!, - process.env.REACT_APP_THORCHAIN_NODE_URL!, + REACT_APP_UNCHAINED_THORCHAIN_HTTP_URL, + REACT_APP_UNCHAINED_THORCHAIN_WS_URL, + REACT_APP_UNCHAINED_THORCHAIN_V1_HTTP_URL, + REACT_APP_THORCHAIN_NODE_URL, ], } diff --git a/react-app-rewired/headers/csps/chatwoot.ts b/react-app-rewired/headers/csps/chatwoot.ts index ec5e82eb851..eb9dc77458e 100644 --- a/react-app-rewired/headers/csps/chatwoot.ts +++ b/react-app-rewired/headers/csps/chatwoot.ts @@ -1,7 +1,11 @@ import type { Csp } from '../types' +const REACT_APP_CHATWOOT_URL = process.env.REACT_APP_CHATWOOT_URL + +if (!REACT_APP_CHATWOOT_URL) throw new Error('REACT_APP_CHATWOOT_URL is required') + export const csp: Csp = { - 'connect-src': [process.env.REACT_APP_CHATWOOT_URL!], - 'script-src': [process.env.REACT_APP_CHATWOOT_URL!], - 'frame-src': [process.env.REACT_APP_CHATWOOT_URL!], + 'connect-src': [REACT_APP_CHATWOOT_URL], + 'script-src': [REACT_APP_CHATWOOT_URL], + 'frame-src': [REACT_APP_CHATWOOT_URL], } diff --git a/react-app-rewired/headers/csps/defi/mtpelerin.ts b/react-app-rewired/headers/csps/defi/mtpelerin.ts index 5bce7dc2c71..aa9dd3b8a6f 100644 --- a/react-app-rewired/headers/csps/defi/mtpelerin.ts +++ b/react-app-rewired/headers/csps/defi/mtpelerin.ts @@ -1,9 +1,17 @@ import type { Csp } from '../../types' +const REACT_APP_MTPELERIN_ASSETS_API = process.env.REACT_APP_MTPELERIN_ASSETS_API +const REACT_APP_MTPELERIN_BUY_URL = process.env.REACT_APP_MTPELERIN_BUY_URL +const REACT_APP_MTPELERIN_SELL_URL = process.env.REACT_APP_MTPELERIN_SELL_URL + +if (!REACT_APP_MTPELERIN_ASSETS_API) throw new Error('REACT_APP_MTPELERIN_ASSETS_API is required') +if (!REACT_APP_MTPELERIN_BUY_URL) throw new Error('REACT_APP_MTPELERIN_BUY_URL is required') +if (!REACT_APP_MTPELERIN_SELL_URL) throw new Error('REACT_APP_MTPELERIN_SELL_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_MTPELERIN_ASSETS_API!, - process.env.REACT_APP_MTPELERIN_BUY_URL!, - process.env.REACT_APP_MTPELERIN_SELL_URL!, + REACT_APP_MTPELERIN_ASSETS_API, + REACT_APP_MTPELERIN_BUY_URL, + REACT_APP_MTPELERIN_SELL_URL, ], } diff --git a/react-app-rewired/headers/csps/fiatRamps/onRamper.ts b/react-app-rewired/headers/csps/fiatRamps/onRamper.ts index 29787fbfb63..ae2537788b3 100644 --- a/react-app-rewired/headers/csps/fiatRamps/onRamper.ts +++ b/react-app-rewired/headers/csps/fiatRamps/onRamper.ts @@ -1,8 +1,12 @@ import type { Csp } from '../../types' +const REACT_APP_ONRAMPER_API_URL = process.env.REACT_APP_ONRAMPER_API_URL +const REACT_APP_ONRAMPER_WIDGET_URL = process.env.REACT_APP_ONRAMPER_WIDGET_URL + +if (!REACT_APP_ONRAMPER_API_URL) throw new Error('REACT_APP_ONRAMPER_API_URL is required') +if (!REACT_APP_ONRAMPER_WIDGET_URL) throw new Error('REACT_APP_ONRAMPER_WIDGET_URL is required') + export const csp: Csp = { - 'connect-src': [ - process.env.REACT_APP_ONRAMPER_API_URL!, - process.env.REACT_APP_ONRAMPER_WIDGET_URL!, - ], + 'connect-src': [REACT_APP_ONRAMPER_API_URL, REACT_APP_ONRAMPER_WIDGET_URL], + 'frame-src': [REACT_APP_ONRAMPER_WIDGET_URL], } diff --git a/react-app-rewired/headers/csps/plugins/foxPage.ts b/react-app-rewired/headers/csps/plugins/foxPage.ts index 2ab55ca5cbd..6d04d164f6c 100644 --- a/react-app-rewired/headers/csps/plugins/foxPage.ts +++ b/react-app-rewired/headers/csps/plugins/foxPage.ts @@ -1,10 +1,20 @@ import type { Csp } from '../../types' +const REACT_APP_TOKEMAK_STATS_URL = process.env.REACT_APP_TOKEMAK_STATS_URL +const REACT_APP_BOARDROOM_API_BASE_URL = process.env.REACT_APP_BOARDROOM_API_BASE_URL + +if (!REACT_APP_TOKEMAK_STATS_URL) throw new Error('REACT_APP_TOKEMAK_STATS_URL is required') +if (!REACT_APP_BOARDROOM_API_BASE_URL) + throw new Error('REACT_APP_BOARDROOM_API_BASE_URL is required') + export const csp: Csp = { 'connect-src': [ - // https://github.com/shapeshift/web/blob/c85fbdd27c360fc09cd8a2aaabec493f9c4e8b78/src/state/apis/foxy/foxyApi.ts#L21 - process.env.REACT_APP_TOKEMAK_STATS_URL!, - // https://github.com/shapeshift/web/blob/965e5f3365e62f02f4cff3d0f78a020e0bf6b376/src/plugins/foxPage/hooks/getGovernanceData.ts#L47 - process.env.REACT_APP_BOARDROOM_API_BASE_URL!, + 'https://raw.githubusercontent.com/Uniswap/token-lists/master/test/schema/example.tokenlist.json', + 'https://raw.githubusercontent.com/Uniswap/default-token-list/master/src/tokens/mainnet.json', + 'https://raw.githubusercontent.com/compound-finance/token-list/master/compound.tokenlist.json', + 'https://api.tokemak.xyz/', + REACT_APP_TOKEMAK_STATS_URL, + 'https://api.boardroom.info/', + REACT_APP_BOARDROOM_API_BASE_URL, ], } diff --git a/react-app-rewired/headers/csps/wallets/keepkey.ts b/react-app-rewired/headers/csps/wallets/keepkey.ts index 87b3e18a300..4598949f728 100644 --- a/react-app-rewired/headers/csps/wallets/keepkey.ts +++ b/react-app-rewired/headers/csps/wallets/keepkey.ts @@ -1,8 +1,11 @@ import type { Csp } from '../../types' +const REACT_APP_KEEPKEY_VERSIONS_URL = process.env.REACT_APP_KEEPKEY_VERSIONS_URL +const REACT_APP_KEEPKEY_DESKTOP_URL = process.env.REACT_APP_KEEPKEY_DESKTOP_URL + +if (!REACT_APP_KEEPKEY_VERSIONS_URL) throw new Error('REACT_APP_KEEPKEY_VERSIONS_URL is required') +if (!REACT_APP_KEEPKEY_DESKTOP_URL) throw new Error('REACT_APP_KEEPKEY_DESKTOP_URL is required') + export const csp: Csp = { - 'connect-src': [ - process.env.REACT_APP_KEEPKEY_VERSIONS_URL!, - process.env.REACT_APP_KEEPKEY_DESKTOP_URL!, - ], + 'connect-src': [REACT_APP_KEEPKEY_VERSIONS_URL, REACT_APP_KEEPKEY_DESKTOP_URL], } diff --git a/react-app-rewired/headers/csps/wallets/walletConnect.ts b/react-app-rewired/headers/csps/wallets/walletConnect.ts index 8f9c9396d08..79e1c4ba9dd 100644 --- a/react-app-rewired/headers/csps/wallets/walletConnect.ts +++ b/react-app-rewired/headers/csps/wallets/walletConnect.ts @@ -1,8 +1,13 @@ import type { Csp } from '../../types' +const REACT_APP_WALLET_CONNECT_RELAY_URL = process.env.REACT_APP_WALLET_CONNECT_RELAY_URL + +if (!REACT_APP_WALLET_CONNECT_RELAY_URL) + throw new Error('REACT_APP_WALLET_CONNECT_RELAY_URL is required') + export const csp: Csp = { 'connect-src': [ - process.env.REACT_APP_WALLET_CONNECT_RELAY_URL!, + REACT_APP_WALLET_CONNECT_RELAY_URL, 'wss://*.bridge.walletconnect.org/', 'wss://*.relay.walletconnect.org/', 'wss://relay.walletconnect.org/', diff --git a/react-app-rewired/headers/csps/wallets/walletMigration.ts b/react-app-rewired/headers/csps/wallets/walletMigration.ts index 258a2b87f79..9dbdd615ff8 100644 --- a/react-app-rewired/headers/csps/wallets/walletMigration.ts +++ b/react-app-rewired/headers/csps/wallets/walletMigration.ts @@ -4,6 +4,6 @@ export const csp: Csp = { 'connect-src': [ // friendly-challenge@0.9.1: https://github.com/FriendlyCaptcha/friendly-challenge/blob/f110634f17f316b90a9bd59b190291abe3c639bb/src/captcha.ts#L20 'https://api.friendlycaptcha.com/api/v1/puzzle', - process.env.REACT_APP_WALLET_MIGRATION_URL!, + process.env.REACT_APP_WALLET_MIGRATION_URL, ], } diff --git a/react-app-rewired/headers/types.ts b/react-app-rewired/headers/types.ts index 130c60720df..e92c32b0132 100644 --- a/react-app-rewired/headers/types.ts +++ b/react-app-rewired/headers/types.ts @@ -1,2 +1,3 @@ -export type Csp = Record -export type CspEntry = [string, string] +// process.env is not properly typed but could be if we were using vite imports.meta. wen vite? +export type Csp = Record +export type CspEntry = (string | undefined)[] diff --git a/react-app-rewired/headers/util.ts b/react-app-rewired/headers/util.ts index 496258add5e..4a9b2dac00e 100644 --- a/react-app-rewired/headers/util.ts +++ b/react-app-rewired/headers/util.ts @@ -9,7 +9,7 @@ import type { Csp, CspEntry } from './types' export function cspToEntries(x: Csp): CspEntry[] { return Object.entries(x).flatMap(([k, v]) => { return v.map(entry => { - const out: [string, string] = [k, entry] + const out = [k, entry] return out }) }) @@ -24,6 +24,9 @@ export function entriesToCsp(x: CspEntry[]): Csp { const acc: Csp = {} return x .sort(([k1, v1], [k2, v2]) => { + if (k1 === undefined || k2 === undefined) return 0 + if (v1 === undefined || v2 === undefined) return 0 + if (k1 < k2) return -1 if (k1 > k2) return 1 if (v1 < v2) return -1 @@ -31,6 +34,8 @@ export function entriesToCsp(x: CspEntry[]): Csp { return 0 }) .reduce((a, [k, v]) => { + if (!k) return a + a[k] ??= [] if (v && (a[k].length === 0 || v !== "'none'") && !a[k].includes(v)) a[k].push(v) if (a[k].length > 1) a[k] = a[k].filter(x => x !== "'none'") From a18cb171d0bb90ba176f47fef7f46cfc41b853ef Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 21 Feb 2025 13:35:23 +0100 Subject: [PATCH 08/13] feat: rerevert --- .eslintrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.eslintrc b/.eslintrc index b591c375e56..5046fae8852 100644 --- a/.eslintrc +++ b/.eslintrc @@ -97,8 +97,8 @@ "react/jsx-handler-names": "error", "require-await": "error", "import/no-duplicates": "error", - "react-memo/require-usememo": "error", - "@typescript-eslint/no-non-null-assertion": "warn" + "react-memo/require-usememo": "error" + // "@typescript-eslint/no-non-null-assertion": "warn" }, "overrides": [ { From f2e889606c9c9eebefd010265e2ec66f77d459d2 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 21 Feb 2025 14:03:42 +0100 Subject: [PATCH 09/13] [skip ci] wip: swapper no-non-null-asserts --- .eslintrc | 4 +- .../ChainflipSwapper/utils/getQuoteOrRate.ts | 59 +++++++++++-------- .../ChainflipSwapper/utils/helpers.ts | 8 ++- .../swappers/CowSwapper/CowSwapper.test.ts | 2 +- .../src/swappers/CowSwapper/endpoints.ts | 8 +-- .../swappers/JupiterSwapper/utils/helpers.ts | 6 +- .../getTradeQuote/getTradeQuote.ts | 21 +++++-- .../swappers/ThorchainSwapper/endpoints.ts | 4 +- .../ThorchainSwapper/utils/getL1Rate.ts | 6 +- .../utils/getL1ToLongtailQuote.ts | 12 +++- .../utils/getL1ToLongtailRate.ts | 12 +++- .../ThorchainSwapper/utils/getL1quote.ts | 4 +- .../helpers/getInputOutputRatioFromQuote.ts | 47 +++++++-------- .../swapper/helpers/validateTradeQuote.ts | 32 +++++----- 14 files changed, 134 insertions(+), 91 deletions(-) diff --git a/.eslintrc b/.eslintrc index 5046fae8852..b591c375e56 100644 --- a/.eslintrc +++ b/.eslintrc @@ -97,8 +97,8 @@ "react/jsx-handler-names": "error", "require-await": "error", "import/no-duplicates": "error", - "react-memo/require-usememo": "error" - // "@typescript-eslint/no-non-null-assertion": "warn" + "react-memo/require-usememo": "error", + "@typescript-eslint/no-non-null-assertion": "warn" }, "overrides": [ { diff --git a/packages/swapper/src/swappers/ChainflipSwapper/utils/getQuoteOrRate.ts b/packages/swapper/src/swappers/ChainflipSwapper/utils/getQuoteOrRate.ts index 5d597076659..36fb06be91e 100644 --- a/packages/swapper/src/swappers/ChainflipSwapper/utils/getQuoteOrRate.ts +++ b/packages/swapper/src/swappers/ChainflipSwapper/utils/getQuoteOrRate.ts @@ -128,12 +128,12 @@ export const getQuoteOrRate = async ( if ( cause.message.includes('code 400') && - cause.response!.data.detail.includes('Amount outside asset bounds') + cause.response?.data.detail.includes('Amount outside asset bounds') ) { return Err( createTradeAmountTooSmallErr({ assetId: sellAsset.assetId, - minAmountCryptoBaseUnit: cause.response!.data.errors.minimalAmountNative[0], + minAmountCryptoBaseUnit: cause.response?.data.errors.minimalAmountNative[0], }), ) } @@ -215,10 +215,13 @@ export const getQuoteOrRate = async ( const getProtocolFees = (singleQuoteResponse: ChainflipBaasQuoteQuote) => { const protocolFees: Record = {} - for (const fee of singleQuoteResponse.includedFees!) { + for (const fee of singleQuoteResponse.includedFees ?? []) { if (fee.type === 'broker') continue - const asset = getFeeAsset(fee)! + const asset = getFeeAsset(fee) + + if (!asset) continue + if (!(asset.assetId in protocolFees)) { protocolFees[asset.assetId] = { amountCryptoBaseUnit: '0', @@ -228,7 +231,7 @@ export const getQuoteOrRate = async ( } protocolFees[asset.assetId].amountCryptoBaseUnit = ( - BigInt(protocolFees[asset.assetId].amountCryptoBaseUnit) + BigInt(fee.amountNative!) + BigInt(protocolFees[asset.assetId].amountCryptoBaseUnit) + BigInt(fee.amountNative ?? '0') ).toString() } @@ -291,17 +294,21 @@ export const getQuoteOrRate = async ( if (!singleQuoteResponse.type) throw new Error('Missing quote type') - if (singleQuoteResponse.boostQuote) { + if ( + singleQuoteResponse.boostQuote && + singleQuoteResponse.boostQuote.ingressAmountNative && + singleQuoteResponse.boostQuote.egressAmountNative + ) { const boostRate = getChainflipQuoteRate( - singleQuoteResponse.boostQuote.ingressAmountNative!, - singleQuoteResponse.boostQuote.egressAmountNative!, + singleQuoteResponse.boostQuote.ingressAmountNative, + singleQuoteResponse.boostQuote.egressAmountNative, ) // This is not really a buyAmount before fees but rather an input/output calculation to get the sell amount // prorated to the buy asset price to determine price impact const buyAmountBeforeFeesCryptoBaseUnit = toBaseUnit( - bnOrZero(singleQuoteResponse.boostQuote.ingressAmount!).times( - singleQuoteResponse.estimatedPrice!, + bnOrZero(singleQuoteResponse.boostQuote.ingressAmount).times( + bnOrZero(singleQuoteResponse.estimatedPrice), ), buyAsset.precision, ) @@ -321,9 +328,9 @@ export const getQuoteOrRate = async ( steps: [ { buyAmountBeforeFeesCryptoBaseUnit, - buyAmountAfterFeesCryptoBaseUnit: singleQuoteResponse.boostQuote.egressAmountNative!, + buyAmountAfterFeesCryptoBaseUnit: singleQuoteResponse.boostQuote.egressAmountNative, sellAmountIncludingProtocolFeesCryptoBaseUnit: - singleQuoteResponse.boostQuote.ingressAmountNative!, + singleQuoteResponse.boostQuote.ingressAmountNative, feeData: { protocolFees: getProtocolFees(singleQuoteResponse.boostQuote), ...feeData, @@ -335,9 +342,8 @@ export const getQuoteOrRate = async ( accountNumber, allowanceContract: '0x0', // Chainflip does not use contracts estimatedExecutionTimeMs: - (singleQuoteResponse.boostQuote.estimatedDurationsSeconds!.deposit! + - singleQuoteResponse.boostQuote.estimatedDurationsSeconds!.swap!) * - 1000, + (singleQuoteResponse.boostQuote.estimatedDurationsSeconds?.deposit ?? 0) + + (singleQuoteResponse.boostQuote.estimatedDurationsSeconds?.swap ?? 0) * 1000, chainflipSpecific: { chainflipNumberOfChunks: isStreaming ? singleQuoteResponse.boostQuote.numberOfChunks ?? undefined @@ -354,15 +360,20 @@ export const getQuoteOrRate = async ( ratesOrQuotes.push(boostTradeRateOrQuote) } - const rate = getChainflipQuoteRate( - singleQuoteResponse.ingressAmountNative!, - singleQuoteResponse.egressAmountNative!, - ) + const rate = + singleQuoteResponse.ingressAmountNative && singleQuoteResponse.egressAmountNative + ? getChainflipQuoteRate( + singleQuoteResponse.ingressAmountNative, + singleQuoteResponse.egressAmountNative, + ) + : '0' // This is not really a buyAmount before fees but rather an input/output calculation to get the sell amount // prorated to the buy asset price to determine price impact const buyAmountBeforeFeesCryptoBaseUnit = toBaseUnit( - bnOrZero(singleQuoteResponse.ingressAmount!).times(singleQuoteResponse.estimatedPrice!), + bnOrZero(singleQuoteResponse.ingressAmount).times( + bnOrZero(singleQuoteResponse.estimatedPrice), + ), buyAsset.precision, ) @@ -381,8 +392,8 @@ export const getQuoteOrRate = async ( steps: [ { buyAmountBeforeFeesCryptoBaseUnit, - buyAmountAfterFeesCryptoBaseUnit: singleQuoteResponse.egressAmountNative!, - sellAmountIncludingProtocolFeesCryptoBaseUnit: singleQuoteResponse.ingressAmountNative!, + buyAmountAfterFeesCryptoBaseUnit: singleQuoteResponse.egressAmountNative, + sellAmountIncludingProtocolFeesCryptoBaseUnit: singleQuoteResponse.ingressAmountNative, feeData: { protocolFees: getProtocolFees(singleQuoteResponse), ...feeData, @@ -394,8 +405,8 @@ export const getQuoteOrRate = async ( accountNumber, allowanceContract: '0x0', // Chainflip does not use contracts - all Txs are sends estimatedExecutionTimeMs: - (singleQuoteResponse.estimatedDurationsSeconds!.deposit! + - singleQuoteResponse.estimatedDurationsSeconds!.swap!) * + ((singleQuoteResponse.estimatedDurationsSeconds?.deposit ?? 0) + + (singleQuoteResponse.estimatedDurationsSeconds?.swap ?? 0)) * 1000, chainflipSpecific: { chainflipNumberOfChunks: isStreaming diff --git a/packages/swapper/src/swappers/ChainflipSwapper/utils/helpers.ts b/packages/swapper/src/swappers/ChainflipSwapper/utils/helpers.ts index e5aef7eab31..6acb4d93001 100644 --- a/packages/swapper/src/swappers/ChainflipSwapper/utils/helpers.ts +++ b/packages/swapper/src/swappers/ChainflipSwapper/utils/helpers.ts @@ -51,9 +51,11 @@ export const isSupportedAssetId = ( chainId: ChainId, assetId: AssetId, ): chainId is ChainflipSupportedChainId => { - return ChainflipSupportedAssetIdsByChainId[chainId as ChainflipSupportedChainId]!.includes( - assetId, - ) + const supportedAssetIds = + ChainflipSupportedAssetIdsByChainId[chainId as ChainflipSupportedChainId] + if (!supportedAssetIds) return false + + return supportedAssetIds.includes(assetId) } export const calculateChainflipMinPrice = ({ diff --git a/packages/swapper/src/swappers/CowSwapper/CowSwapper.test.ts b/packages/swapper/src/swappers/CowSwapper/CowSwapper.test.ts index a2322ed5cee..e8fb243c5ad 100644 --- a/packages/swapper/src/swappers/CowSwapper/CowSwapper.test.ts +++ b/packages/swapper/src/swappers/CowSwapper/CowSwapper.test.ts @@ -288,7 +288,7 @@ describe('cowApi', () => { Ok({ data: cowswapQuoteResponse } as unknown as AxiosResponse), ), ) - const actual = await cowApi.getUnsignedEvmMessage!({ + const actual = await cowApi.getUnsignedEvmMessage?.({ from, slippageTolerancePercentageDecimal, tradeQuote, diff --git a/packages/swapper/src/swappers/CowSwapper/endpoints.ts b/packages/swapper/src/swappers/CowSwapper/endpoints.ts index b4c927c889f..d1b69801b79 100644 --- a/packages/swapper/src/swappers/CowSwapper/endpoints.ts +++ b/packages/swapper/src/swappers/CowSwapper/endpoints.ts @@ -44,9 +44,9 @@ export const cowApi: SwapperApi = { return tradeQuoteResult.map(tradeQuote => { // A quote always has a first step - const firstStep = getHopByIndex(tradeQuote, 0)! + const firstStep = getHopByIndex(tradeQuote, 0) const id = uuid() - tradeQuoteMetadata.set(id, { chainId: firstStep.sellAsset.chainId as EvmChainId }) + tradeQuoteMetadata.set(id, { chainId: firstStep?.sellAsset.chainId as EvmChainId }) return [tradeQuote] }) }, @@ -58,9 +58,9 @@ export const cowApi: SwapperApi = { return tradeRateResult.map(tradeRate => { // A rate always has a first step - const firstStep = getHopByIndex(tradeRate, 0)! + const firstStep = getHopByIndex(tradeRate, 0) const id = uuid() - tradeQuoteMetadata.set(id, { chainId: firstStep.sellAsset.chainId as EvmChainId }) + tradeQuoteMetadata.set(id, { chainId: firstStep?.sellAsset.chainId as EvmChainId }) return [tradeRate] }) }, diff --git a/packages/swapper/src/swappers/JupiterSwapper/utils/helpers.ts b/packages/swapper/src/swappers/JupiterSwapper/utils/helpers.ts index 0a861a56200..adb2c15f38d 100644 --- a/packages/swapper/src/swappers/JupiterSwapper/utils/helpers.ts +++ b/packages/swapper/src/swappers/JupiterSwapper/utils/helpers.ts @@ -223,10 +223,10 @@ export const createSwapInstructions = async ({ buyAsset.assetId === solAssetId ? undefined : fromAssetId(buyAsset.assetId).assetReference const { instruction: createTokenAccountInstruction, destinationTokenAccount } = - contractAddress && isCrossAccountTrade + contractAddress && isCrossAccountTrade && receiveAddress ? await adapter.createAssociatedTokenAccountInstruction({ from: sendAddress, - to: receiveAddress!, + to: receiveAddress, tokenId: contractAddress, }) : { instruction: undefined, destinationTokenAccount: undefined } @@ -277,7 +277,7 @@ export const createSwapInstructions = async ({ if (maybeSwapResponse.isErr()) { const error = maybeSwapResponse.unwrapErr() const cause = error.cause as AxiosError - throw Error(cause.response!.data.detail) + throw Error(cause.response?.data.detail) } const { data: swapResponse } = maybeSwapResponse.unwrap() diff --git a/packages/swapper/src/swappers/LifiSwapper/getTradeQuote/getTradeQuote.ts b/packages/swapper/src/swappers/LifiSwapper/getTradeQuote/getTradeQuote.ts index d1be319a8d2..d9f8f6aaa42 100644 --- a/packages/swapper/src/swappers/LifiSwapper/getTradeQuote/getTradeQuote.ts +++ b/packages/swapper/src/swappers/LifiSwapper/getTradeQuote/getTradeQuote.ts @@ -9,6 +9,7 @@ import { convertPrecision, isFulfilled, isRejected, + isSome, } from '@shapeshiftoss/utils' import type { Result } from '@sniptt/monads' import { Err, Ok } from '@sniptt/monads' @@ -350,11 +351,19 @@ export const getTradeQuote = async ( const quotesResult = await getTrade({ input, deps, lifiChainMap }) return quotesResult.map(quotes => - quotes.map(quote => ({ - ...quote, - quoteOrRate: 'quote' as const, - receiveAddress: quote.receiveAddress!, - steps: quote.steps.map(step => step) as [TradeQuoteStep] | [TradeQuoteStep, TradeQuoteStep], - })), + quotes + .map(quote => { + if (!quote.receiveAddress) return undefined + + return { + ...quote, + quoteOrRate: 'quote' as const, + receiveAddress: quote.receiveAddress, + steps: quote.steps.map(step => step) as + | [TradeQuoteStep] + | [TradeQuoteStep, TradeQuoteStep], + } + }) + .filter(isSome), ) } diff --git a/packages/swapper/src/swappers/ThorchainSwapper/endpoints.ts b/packages/swapper/src/swappers/ThorchainSwapper/endpoints.ts index 488166e33e5..668c56fc30e 100644 --- a/packages/swapper/src/swappers/ThorchainSwapper/endpoints.ts +++ b/packages/swapper/src/swappers/ThorchainSwapper/endpoints.ts @@ -434,7 +434,7 @@ export const thorchainApi: SwapperApi = { return assertGetUtxoChainAdapter(sellAsset.chainId).buildSendApiTransaction({ value: sellAmountIncludingProtocolFeesCryptoBaseUnit, - xpub: xpub!, + xpub, to: vault, accountNumber, // skip address validation for thorchain vault addresses as they may exceed the risk score threshold, but are still valid for use @@ -475,7 +475,7 @@ export const thorchainApi: SwapperApi = { to: vault, value: firstStep.sellAmountIncludingProtocolFeesCryptoBaseUnit, chainSpecific: { - pubkey: xpub!, + pubkey: xpub, opReturnData, }, sendMax: false, diff --git a/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1Rate.ts b/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1Rate.ts index 6410cdc9e9b..e7d0b0ae4f1 100644 --- a/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1Rate.ts +++ b/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1Rate.ts @@ -280,7 +280,7 @@ export const getL1Rate = async ( source, buyAsset, sellAsset, - accountNumber: accountNumber!, + accountNumber, allowanceContract: router, feeData: { networkFeeCryptoBaseUnit, @@ -342,7 +342,7 @@ export const getL1Rate = async ( const { vault, opReturnData, pubkey } = await getUtxoThorTxInfo({ sellAsset, - xpub: (input as unknown as GetUtxoTradeQuoteInput).xpub!, + xpub: (input as unknown as GetUtxoTradeQuoteInput).xpub, memo, config: deps.config, }) @@ -392,7 +392,7 @@ export const getL1Rate = async ( sellAsset, // TODO(gomes): when we actually split between TradeQuote and TradeRate in https://github.com/shapeshift/web/issues/7941, // this won't be an issue anymore - for now this is tackled at runtime with the isConnected check above - accountNumber: accountNumber!, + accountNumber, allowanceContract: '0x0', // not applicable to UTXOs feeData, }, diff --git a/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1ToLongtailQuote.ts b/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1ToLongtailQuote.ts index 13cdb20094e..9e27917a051 100644 --- a/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1ToLongtailQuote.ts +++ b/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1ToLongtailQuote.ts @@ -118,7 +118,17 @@ export const getL1ToLongtailQuote = async ( const promises = await Promise.allSettled( thorchainQuotes.map(async quote => { // A quote always has a first step - const onlyStep = getHopByIndex(quote, 0)! + const onlyStep = getHopByIndex(quote, 0) + + // Or well... it should. + if (!onlyStep) { + return Err( + makeSwapErrorRight({ + message: `[getL1ToLongtailQuote] - First hop not found`, + code: TradeQuoteError.InternalError, + }), + ) + } const maybeBestAggregator = await getBestAggregator( buyAssetFeeAsset, diff --git a/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1ToLongtailRate.ts b/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1ToLongtailRate.ts index 3ee3ca7e629..661b77c678b 100644 --- a/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1ToLongtailRate.ts +++ b/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1ToLongtailRate.ts @@ -109,7 +109,17 @@ export const getL1ToLongtailRate = async ( const promises = await Promise.allSettled( thorchainRates.map(async quote => { // A quote always has a first step - const onlyStep = getHopByIndex(quote, 0)! + const onlyStep = getHopByIndex(quote, 0) + + // Or well... it should. + if (!onlyStep) { + return Err( + makeSwapErrorRight({ + message: `[getL1ToLongtailRate] - First hop not found`, + code: TradeQuoteError.InternalError, + }), + ) + } const maybeBestAggregator = await getBestAggregator( buyAssetFeeAsset, diff --git a/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1quote.ts b/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1quote.ts index d834837d6e0..a280ad1ccfa 100644 --- a/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1quote.ts +++ b/packages/swapper/src/swappers/ThorchainSwapper/utils/getL1quote.ts @@ -294,7 +294,7 @@ export const getL1Quote = async ( source, buyAsset, sellAsset, - accountNumber: accountNumber!, + accountNumber, allowanceContract: router, feeData: { networkFeeCryptoBaseUnit, @@ -360,7 +360,7 @@ export const getL1Quote = async ( const { vault, opReturnData, pubkey } = await getUtxoThorTxInfo({ sellAsset, - xpub: (input as GetUtxoTradeQuoteInput).xpub!, + xpub: (input as GetUtxoTradeQuoteInput).xpub, memo, config: deps.config, }) diff --git a/src/state/apis/swapper/helpers/getInputOutputRatioFromQuote.ts b/src/state/apis/swapper/helpers/getInputOutputRatioFromQuote.ts index a6bfdb2a3bc..dfc32841b89 100644 --- a/src/state/apis/swapper/helpers/getInputOutputRatioFromQuote.ts +++ b/src/state/apis/swapper/helpers/getInputOutputRatioFromQuote.ts @@ -103,38 +103,39 @@ export const getInputOutputRatioFromQuote = ({ swapperName: SwapperName }): number => { // A quote always has a first step - const firstStep = getHopByIndex(quote, 0)! - const { sellAmountIncludingProtocolFeesCryptoBaseUnit, sellAsset } = firstStep + const firstStep = getHopByIndex(quote, 0) + const { sellAmountIncludingProtocolFeesCryptoBaseUnit, sellAsset } = firstStep ?? {} const lastStepIndex = (quote.steps.length - 1) as SupportedTradeQuoteStepIndex // A quote always has a last step since it always has a first - const lastStep = getHopByIndex(quote, lastStepIndex)! - const { buyAsset, buyAmountAfterFeesCryptoBaseUnit: netReceiveAmountCryptoBaseUnit } = lastStep + const lastStep = getHopByIndex(quote, lastStepIndex) + const { buyAsset, buyAmountAfterFeesCryptoBaseUnit: netReceiveAmountCryptoBaseUnit } = + lastStep ?? {} // If we are trading custom assets we might not have USD rates, so we cannot determine a ratio - const hasSellAssetUsdRate = selectUsdRateByAssetId(state, sellAsset.assetId) !== undefined - const hasBuyAssetUsdRate = selectUsdRateByAssetId(state, buyAsset.assetId) !== undefined + const hasSellAssetUsdRate = selectUsdRateByAssetId(state, sellAsset?.assetId ?? '') !== undefined + const hasBuyAssetUsdRate = selectUsdRateByAssetId(state, buyAsset?.assetId ?? '') !== undefined if (!hasSellAssetUsdRate || !hasBuyAssetUsdRate) return 0 // TODO: implement this when we do multi-hop const buySideNetworkFeeCryptoBaseUnit = bn(0) - const netReceiveAmountUsdPrecision = _convertCryptoBaseUnitToUsdPrecision( - state, - buyAsset, - netReceiveAmountCryptoBaseUnit, - ) - - const buySideNetworkFeeUsdPrecision = _convertCryptoBaseUnitToUsdPrecision( - state, - buyAsset, - buySideNetworkFeeCryptoBaseUnit, - ) - - const sellAmountCryptoBaseUnit = _convertCryptoBaseUnitToUsdPrecision( - state, - sellAsset, - sellAmountIncludingProtocolFeesCryptoBaseUnit, - ) + const netReceiveAmountUsdPrecision = + buyAsset && netReceiveAmountCryptoBaseUnit + ? _convertCryptoBaseUnitToUsdPrecision(state, buyAsset, netReceiveAmountCryptoBaseUnit) + : bn(0) + + const buySideNetworkFeeUsdPrecision = buyAsset + ? _convertCryptoBaseUnitToUsdPrecision(state, buyAsset, buySideNetworkFeeCryptoBaseUnit) + : bn(0) + + const sellAmountCryptoBaseUnit = + sellAsset && sellAmountIncludingProtocolFeesCryptoBaseUnit + ? _convertCryptoBaseUnitToUsdPrecision( + state, + sellAsset, + sellAmountIncludingProtocolFeesCryptoBaseUnit, + ) + : bn(0) const totalNetworkFeeUsdPrecision = _getTotalNetworkFeeUsdPrecision(state, quote) diff --git a/src/state/apis/swapper/helpers/validateTradeQuote.ts b/src/state/apis/swapper/helpers/validateTradeQuote.ts index baf4166316b..832f38fcf6c 100644 --- a/src/state/apis/swapper/helpers/validateTradeQuote.ts +++ b/src/state/apis/swapper/helpers/validateTradeQuote.ts @@ -131,21 +131,21 @@ export const validateTradeQuote = ( const walletId = selectWalletId(state) // A quote always consists of at least one hop - const firstHop = getHopByIndex(quote, 0)! + const firstHop = getHopByIndex(quote, 0) const secondHop = getHopByIndex(quote, 1) const isMultiHopTrade = isExecutableTradeQuote(quote) ? isMultiHopTradeQuote(quote) : isMultiHopTradeRate(quote) - const lastHop = (isMultiHopTrade ? secondHop : firstHop)! + const lastHop = isMultiHopTrade ? secondHop : firstHop const walletConnectedChainIds = selectWalletConnectedChainIds(state) const sellAmountCryptoPrecision = selectInputSellAmountCryptoPrecision(state) - const sellAmountCryptoBaseUnit = firstHop.sellAmountIncludingProtocolFeesCryptoBaseUnit - const buyAmountCryptoBaseUnit = lastHop.buyAmountBeforeFeesCryptoBaseUnit + const sellAmountCryptoBaseUnit = firstHop?.sellAmountIncludingProtocolFeesCryptoBaseUnit + const buyAmountCryptoBaseUnit = lastHop?.buyAmountBeforeFeesCryptoBaseUnit // the network fee asset for the first hop in the trade - const firstHopSellFeeAsset = selectFeeAssetById(state, firstHop.sellAsset.assetId) + const firstHopSellFeeAsset = selectFeeAssetById(state, firstHop?.sellAsset.assetId ?? '') // the network fee asset for the second hop in the trade const secondHopSellFeeAsset = @@ -174,7 +174,7 @@ export const validateTradeQuote = ( const firstHopNetworkFeeCryptoPrecision = networkFeeRequiresBalance && firstHopSellFeeAsset ? fromBaseUnit( - bnOrZero(firstHop.feeData.networkFeeCryptoBaseUnit), + bnOrZero(firstHop?.feeData.networkFeeCryptoBaseUnit), firstHopSellFeeAsset.precision, ) : bn(0).toFixed() @@ -188,12 +188,12 @@ export const validateTradeQuote = ( : bn(0).toFixed() const firstHopTradeDeductionCryptoPrecision = - firstHopSellFeeAsset?.assetId === firstHop.sellAsset.assetId + firstHopSellFeeAsset?.assetId === firstHop?.sellAsset.assetId ? bnOrZero(sellAmountCryptoPrecision).toFixed() : bn(0).toFixed() const walletSupportsIntermediaryAssetChain = - !isMultiHopTrade || walletConnectedChainIds.includes(firstHop.buyAsset.chainId) + !isMultiHopTrade || walletConnectedChainIds.includes(firstHop?.buyAsset.chainId ?? '') const firstHopHasSufficientBalanceForGas = bnOrZero(firstHopFeeAssetBalancePrecision) .minus(firstHopNetworkFeeCryptoPrecision ?? 0) @@ -212,8 +212,8 @@ export const validateTradeQuote = ( const portfolioAccountIdByNumberByChainId = selectPortfolioAccountIdByNumberByChainId(state) const portfolioAccountBalancesBaseUnit = selectPortfolioAccountBalancesBaseUnit(state) - const sellAssetAccountNumber = firstHop.accountNumber - const totalProtocolFeesByAsset = getTotalProtocolFeeByAssetForStep(firstHop) + const sellAssetAccountNumber = firstHop?.accountNumber + const totalProtocolFeesByAsset = firstHop ? getTotalProtocolFeeByAssetForStep(firstHop) : {} // This is an oversimplification where protocol fees are assumed to be only deducted from // account IDs corresponding to the sell asset account number and protocol fee asset chain ID. @@ -233,11 +233,11 @@ export const validateTradeQuote = ( // them kick the swapperName bit out of the condition if ( firstHopSellFeeAsset?.assetId === assetId && - firstHop.sellAsset.assetId === assetId && + firstHop?.sellAsset.assetId === assetId && swapperName === SwapperName.Jupiter ) { return bnOrZero(balanceCryptoBaseUnit) - .minus(sellAmountCryptoBaseUnit) + .minus(bnOrZero(sellAmountCryptoBaseUnit)) .minus(protocolFee.amountCryptoBaseUnit) .lt(0) } @@ -267,7 +267,7 @@ export const validateTradeQuote = ( // Ensure the trade is not selling an amount higher than the user input, within a very safe threshold. // Threshold is required because cowswap sometimes quotes a sell amount a teeny-tiny bit more than you input. const invalidQuoteSellAmount = bn(inputSellAmountCryptoBaseUnit).lt( - firstHop.sellAmountIncludingProtocolFeesCryptoBaseUnit, + bnOrZero(firstHop?.sellAmountIncludingProtocolFeesCryptoBaseUnit), ) return { @@ -276,7 +276,7 @@ export const validateTradeQuote = ( error: TradeQuoteValidationError.TradingInactiveOnSellChain, meta: { chainName: assertGetChainAdapter( - firstHop.sellAsset.chainId as KnownChainIds, + firstHop?.sellAsset.chainId as KnownChainIds, ).getDisplayName(), }, }, @@ -284,7 +284,7 @@ export const validateTradeQuote = ( error: TradeQuoteValidationError.TradingInactiveOnBuyChain, meta: { chainName: assertGetChainAdapter( - firstHop.buyAsset.chainId as KnownChainIds, + firstHop?.buyAsset.chainId as KnownChainIds, ).getDisplayName(), }, }, @@ -300,7 +300,7 @@ export const validateTradeQuote = ( walletId && !firstHopHasSufficientBalanceForGas && { error: - firstHopSellFeeAsset?.assetId === firstHop.sellAsset.assetId + firstHopSellFeeAsset?.assetId === firstHop?.sellAsset.assetId ? TradeQuoteValidationError.InsufficientFirstHopAssetBalance : TradeQuoteValidationError.InsufficientFirstHopFeeAssetBalance, meta: { From 563602b3fb1dab6625d0296fe88d12ee181c6e50 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 21 Feb 2025 14:33:42 +0100 Subject: [PATCH 10/13] [skip ci] wip: wip --- .../ArbitrumBridgeSwapper/endpoints.ts | 13 ++++++-- .../utils/fetchArbitrumBridgeSwap.ts | 23 +++++++++----- .../swappers/ChainflipSwapper/endpoints.ts | 12 ++++--- .../swapperApi/getTradeQuote.ts | 31 +++++++++++++------ .../TradeInput/components/ConfirmSummary.tsx | 3 +- .../components/TradeSuccess/TradeSuccess.tsx | 8 ++--- .../hooks/quoteValidation/usePriceImpact.tsx | 8 ++--- src/state/apis/snapshot/selectors.ts | 3 +- .../createTradeInputBaseSlice.ts | 2 +- 9 files changed, 67 insertions(+), 36 deletions(-) diff --git a/packages/swapper/src/swappers/ArbitrumBridgeSwapper/endpoints.ts b/packages/swapper/src/swappers/ArbitrumBridgeSwapper/endpoints.ts index c1a7c8bb7a0..0e11d639816 100644 --- a/packages/swapper/src/swappers/ArbitrumBridgeSwapper/endpoints.ts +++ b/packages/swapper/src/swappers/ArbitrumBridgeSwapper/endpoints.ts @@ -95,7 +95,11 @@ export const arbitrumBridgeApi: SwapperApi = { return tradeQuoteResult.map(tradeQuote => { const id = tradeQuote.id - const firstHop = getHopByIndex(tradeQuote, 0)! + const firstHop = getHopByIndex(tradeQuote, 0) + if (!firstHop) { + console.error('No first hop found in trade quote') + return [] + } tradeQuoteMetadata.set(id, { sellAssetId: firstHop.sellAsset.assetId, chainId: firstHop.sellAsset.chainId as EvmChainId, @@ -111,7 +115,12 @@ export const arbitrumBridgeApi: SwapperApi = { return tradeRateResult.map(tradeQuote => { const id = tradeQuote.id - const firstHop = getHopByIndex(tradeQuote, 0)! + const firstHop = getHopByIndex(tradeQuote, 0) + if (!firstHop) { + console.error('No first hop found in trade rate') + return [] + } + tradeQuoteMetadata.set(id, { sellAssetId: firstHop.sellAsset.assetId, chainId: firstHop.sellAsset.chainId as EvmChainId, diff --git a/packages/swapper/src/swappers/ArbitrumBridgeSwapper/utils/fetchArbitrumBridgeSwap.ts b/packages/swapper/src/swappers/ArbitrumBridgeSwapper/utils/fetchArbitrumBridgeSwap.ts index fc24b75a33d..444ab10749e 100644 --- a/packages/swapper/src/swappers/ArbitrumBridgeSwapper/utils/fetchArbitrumBridgeSwap.ts +++ b/packages/swapper/src/swappers/ArbitrumBridgeSwapper/utils/fetchArbitrumBridgeSwap.ts @@ -99,8 +99,10 @@ const fetchArbitrumBridgeSwap = async ({ parentProvider, childProvider, amount: BigNumber.from(sellAmountIncludingProtocolFeesCryptoBaseUnit), - from: sendAddress!, - destinationAddress: receiveAddress!, + // This is actually guarded against in if `(quoteOrRate === 'quote' && !sendAddress)` above + from: sendAddress ?? '', + // This is actually guarded against in if `(quoteOrRate === 'quote' && !receiveAddress)` above + destinationAddress: receiveAddress ?? '', }) .catch(e => { console.error('Error getting ETH deposit request', e) @@ -125,8 +127,10 @@ const fetchArbitrumBridgeSwap = async ({ ? await bridger .getWithdrawalRequest({ amount: BigNumber.from(sellAmountIncludingProtocolFeesCryptoBaseUnit), - from: sendAddress!, - destinationAddress: receiveAddress!, + // This is actually guarded against in if `(quoteOrRate === 'quote' && !sendAddress)` above + from: sendAddress ?? '', + // This is actually guarded against in if `(quoteOrRate === 'quote' && !receiveAddress)` above + destinationAddress: receiveAddress ?? '', }) .catch(e => { console.error('Error getting ETH withdraw request', e) @@ -159,8 +163,9 @@ const fetchArbitrumBridgeSwap = async ({ parentProvider, childProvider, erc20ParentAddress, - from: sendAddress!, - destinationAddress: receiveAddress!, + // This is actually guarded against in if `(quoteOrRate === 'quote' && !sendAddress)` above + from: sendAddress ?? '', + destinationAddress: receiveAddress, retryableGasOverrides: { // https://github.com/OffchainLabs/arbitrum-token-bridge/blob/d17c88ef3eef3f4ffc61a04d34d50406039f045d/packages/arb-token-bridge-ui/src/util/TokenDepositUtils.ts#L159 // the gas limit may vary by about 20k due to SSTORE (zero vs nonzero) @@ -193,8 +198,10 @@ const fetchArbitrumBridgeSwap = async ({ .getWithdrawalRequest({ amount: BigNumber.from(sellAmountIncludingProtocolFeesCryptoBaseUnit), erc20ParentAddress, - from: sendAddress!, - destinationAddress: receiveAddress!, + // This is actually guarded against in if `(quoteOrRate === 'quote' && !sendAddress)` above + from: sendAddress ?? '', + // This is actually guarded against in if `(quoteOrRate === 'quote' && !receiveAddress)` above + destinationAddress: receiveAddress ?? '', }) .catch(e => { console.error('Error getting ERC20 withdraw request', e) diff --git a/packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts b/packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts index 059f4b10bff..dfa4a070296 100644 --- a/packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts +++ b/packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts @@ -73,10 +73,12 @@ export const chainflipApi: SwapperApi = { chainSpecific: { gasLimit: fees.chainSpecific.gasLimit, contractAddress: isTokenSend ? assetReference : undefined, - ...(supportsEIP1559 + ...(supportsEIP1559 && + fees.chainSpecific.maxFeePerGas && + fees.chainSpecific.maxPriorityFeePerGas ? { - maxFeePerGas: fees.chainSpecific.maxFeePerGas!, - maxPriorityFeePerGas: fees.chainSpecific.maxPriorityFeePerGas!, + maxFeePerGas: fees.chainSpecific.maxFeePerGas, + maxPriorityFeePerGas: fees.chainSpecific.maxPriorityFeePerGas, } : { gasPrice: fees.chainSpecific.gasPrice, @@ -150,7 +152,7 @@ export const chainflipApi: SwapperApi = { return adapter.buildSendApiTransaction({ value: step.sellAmountIncludingProtocolFeesCryptoBaseUnit, - xpub: xpub!, + xpub, to: step.chainflipSpecific.chainflipDepositAddress, accountNumber: step.accountNumber, skipToAddressValidation: true, @@ -177,7 +179,7 @@ export const chainflipApi: SwapperApi = { to: step.chainflipSpecific.chainflipDepositAddress, value: step.sellAmountIncludingProtocolFeesCryptoBaseUnit, chainSpecific: { - pubkey: xpub!, + pubkey: xpub, }, sendMax: false, } diff --git a/packages/swapper/src/swappers/ChainflipSwapper/swapperApi/getTradeQuote.ts b/packages/swapper/src/swappers/ChainflipSwapper/swapperApi/getTradeQuote.ts index 368b191502f..b0fcd5669c1 100644 --- a/packages/swapper/src/swappers/ChainflipSwapper/swapperApi/getTradeQuote.ts +++ b/packages/swapper/src/swappers/ChainflipSwapper/swapperApi/getTradeQuote.ts @@ -1,6 +1,7 @@ import { CHAIN_NAMESPACE, fromAssetId, solAssetId } from '@shapeshiftoss/caip' import type { GetFeeDataInput } from '@shapeshiftoss/chain-adapters' import type { KnownChainIds } from '@shapeshiftoss/types' +import { isSome } from '@shapeshiftoss/utils' import type { Result } from '@sniptt/monads' import { Err, Ok } from '@sniptt/monads' import type { AxiosError } from 'axios' @@ -103,8 +104,8 @@ export const getTradeQuote = async ( sourceAsset, minimumPrice, destinationAsset, - destinationAddress: input.receiveAddress, - refundAddress: input.sendAddress!, + destinationAddress: receiveAddress, + refundAddress: sendAddress, maxBoostFee: step.chainflipSpecific?.chainflipMaxBoostFee, numberOfChunks: step.chainflipSpecific?.chainflipNumberOfChunks, chunkIntervalBlocks: step.chainflipSpecific?.chainflipChunkIntervalBlocks, @@ -114,7 +115,7 @@ export const getTradeQuote = async ( if (maybeSwapResponse.isErr()) { const error = maybeSwapResponse.unwrapErr() const cause = error.cause as AxiosError - throw Error(cause.response!.data.detail) + throw Error(cause.response?.data.detail) } const { data: swapResponse } = maybeSwapResponse.unwrap() @@ -135,7 +136,7 @@ export const getTradeQuote = async ( to: depositAddress, value: sellAmount, chainSpecific: { - from: input.sendAddress!, + from: sendAddress, tokenId: sellAsset.assetId === solAssetId ? undefined @@ -169,11 +170,21 @@ export const getTradeQuote = async ( const quotesResult = Ok(tradeQuotes) return quotesResult.map(quotes => - quotes.map(quote => ({ - ...quote, - quoteOrRate: 'quote' as const, - receiveAddress: receiveAddress!, - steps: quote.steps.map(step => step) as [TradeQuoteStep] | [TradeQuoteStep, TradeQuoteStep], - })), + quotes + .map(quote => { + if (!quote.receiveAddress) { + console.error('receiveAddress is required') + return undefined + } + return { + ...quote, + quoteOrRate: 'quote' as const, + receiveAddress, + steps: quote.steps.map(step => step) as + | [TradeQuoteStep] + | [TradeQuoteStep, TradeQuoteStep], + } + }) + .filter(isSome), ) } diff --git a/src/components/MultiHopTrade/components/TradeInput/components/ConfirmSummary.tsx b/src/components/MultiHopTrade/components/TradeInput/components/ConfirmSummary.tsx index 36dda4b9f3a..4e1dde4d269 100644 --- a/src/components/MultiHopTrade/components/TradeInput/components/ConfirmSummary.tsx +++ b/src/components/MultiHopTrade/components/TradeInput/components/ConfirmSummary.tsx @@ -254,7 +254,8 @@ export const ConfirmSummary = ({ tradeQuoteError.error === TradeQuoteError.FinalQuoteExecutionReverted): return 'trade.previewTrade' case !!tradeQuoteError: - return getQuoteErrorTranslation(tradeQuoteError!) + // TS pls + return tradeQuoteError ? getQuoteErrorTranslation(tradeQuoteError) : 'common.error' case !isAnyTradeQuoteLoading && !isAnySwapperQuoteAvailable: return 'trade.noRateAvailable' case !isConnected || isDemoWallet: diff --git a/src/components/MultiHopTrade/components/TradeSuccess/TradeSuccess.tsx b/src/components/MultiHopTrade/components/TradeSuccess/TradeSuccess.tsx index 23dc443ad6b..ffd67685fab 100644 --- a/src/components/MultiHopTrade/components/TradeSuccess/TradeSuccess.tsx +++ b/src/components/MultiHopTrade/components/TradeSuccess/TradeSuccess.tsx @@ -195,11 +195,11 @@ export const TradeSuccess = ({ - {enableFoxDiscountSummary && hasFeeSaving && ( - + {enableFoxDiscountSummary && hasFeeSaving && feeSavingUserCurrency && ( + )} - {couldHaveReducedFee && ( - + {couldHaveReducedFee && affiliateFeeUserCurrency && ( + )} diff --git a/src/components/MultiHopTrade/hooks/quoteValidation/usePriceImpact.tsx b/src/components/MultiHopTrade/hooks/quoteValidation/usePriceImpact.tsx index 15d066fc10c..b82105cdf89 100644 --- a/src/components/MultiHopTrade/hooks/quoteValidation/usePriceImpact.tsx +++ b/src/components/MultiHopTrade/hooks/quoteValidation/usePriceImpact.tsx @@ -26,9 +26,9 @@ export const usePriceImpact = (tradeQuote: TradeQuote | TradeRate | undefined) = if (!tradeQuote || !sellAsset || !sellAssetUsdRate) return // A quote always has a first hop - const firstHop = getHopByIndex(tradeQuote, 0)! + const firstHop = getHopByIndex(tradeQuote, 0) const sellAmountIncludingProtocolFeesCryptoBaseUnit = - firstHop.sellAmountIncludingProtocolFeesCryptoBaseUnit + firstHop?.sellAmountIncludingProtocolFeesCryptoBaseUnit const sellAmountIncludingProtocolFeesCryptoPrecision = fromBaseUnit( sellAmountIncludingProtocolFeesCryptoBaseUnit, @@ -50,9 +50,9 @@ export const usePriceImpact = (tradeQuote: TradeQuote | TradeRate | undefined) = const lastHopIndex = (numSteps - 1) as SupportedTradeQuoteStepIndex // A quote always has a last hop since it always has a first hop - const lastHop = getHopByIndex(tradeQuote, lastHopIndex)! + const lastHop = getHopByIndex(tradeQuote, lastHopIndex) const buyAmountBeforeFeesCryptoPrecision = fromBaseUnit( - lastHop.buyAmountBeforeFeesCryptoBaseUnit, + lastHop?.buyAmountBeforeFeesCryptoBaseUnit, buyAsset.precision, ) diff --git a/src/state/apis/snapshot/selectors.ts b/src/state/apis/snapshot/selectors.ts index c49c9077f2d..3c7933a67d9 100644 --- a/src/state/apis/snapshot/selectors.ts +++ b/src/state/apis/snapshot/selectors.ts @@ -33,12 +33,13 @@ export const selectVotingPower = createSelector( selectAccountIdsByChainId, selectIsSnapshotApiQueriesRejected, (votingPowerByModel, feeModel, accountIdsbyChainId, isSnapshotApiQueriesRejected) => { + if (!feeModel) return '0' if (isSnapshotApiQueriesRejected) return '0' const ethAccountIds = accountIdsbyChainId[ethChainId] if (!ethAccountIds?.length) return '0' - return votingPowerByModel[feeModel!] + return votingPowerByModel[feeModel] }, ) diff --git a/src/state/slices/common/tradeInputBase/createTradeInputBaseSlice.ts b/src/state/slices/common/tradeInputBase/createTradeInputBaseSlice.ts index 6e0adea182d..ee530f4f532 100644 --- a/src/state/slices/common/tradeInputBase/createTradeInputBaseSlice.ts +++ b/src/state/slices/common/tradeInputBase/createTradeInputBaseSlice.ts @@ -74,7 +74,7 @@ const getBaseReducers = (initialState: T) => ({ // Avoid division by zero state.sellAmountCryptoPrecision = bnOrZero(buyAssetUsdRate).isZero() ? '0' - : sellAmountUsd.div(buyAssetUsdRate!).toFixed() + : sellAmountUsd.div(bnOrZero(buyAssetUsdRate)).toFixed() const buyAsset = state.sellAsset state.sellAsset = state.buyAsset From e6f5ea4d858d9b8a7ef20fdd3fc9fd7e4f046776 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 21 Feb 2025 15:42:05 +0100 Subject: [PATCH 11/13] feat: done --- .../hooks/useChainflipStreamingProgress.tsx | 6 ++--- .../VerifyAddresses/VerifyAddresses.tsx | 23 +++++++++++-------- .../hooks/useInputOutputDifference.ts | 12 +++++----- .../hooks/useQuoteEstimatedFeesQuery.ts | 23 ++++++++++--------- 4 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/components/MultiHopTrade/components/TradeConfirm/hooks/useChainflipStreamingProgress.tsx b/src/components/MultiHopTrade/components/TradeConfirm/hooks/useChainflipStreamingProgress.tsx index e532ba14729..895d0d7c2ed 100644 --- a/src/components/MultiHopTrade/components/TradeConfirm/hooks/useChainflipStreamingProgress.tsx +++ b/src/components/MultiHopTrade/components/TradeConfirm/hooks/useChainflipStreamingProgress.tsx @@ -56,14 +56,14 @@ const getChainflipStreamingSwap = async ( ) { // It's finished! return { - executedChunks: dcaStatus!.executedChunks!, + executedChunks: dcaStatus.executedChunks ?? 0, remainingChunks: 0, } } return { - executedChunks: dcaStatus!.executedChunks!, - remainingChunks: dcaStatus!.remainingChunks!, + executedChunks: dcaStatus?.executedChunks ?? 0, + remainingChunks: dcaStatus?.remainingChunks ?? 0, } } diff --git a/src/components/MultiHopTrade/components/VerifyAddresses/VerifyAddresses.tsx b/src/components/MultiHopTrade/components/VerifyAddresses/VerifyAddresses.tsx index c52de7115ad..5181a7ecd81 100644 --- a/src/components/MultiHopTrade/components/VerifyAddresses/VerifyAddresses.tsx +++ b/src/components/MultiHopTrade/components/VerifyAddresses/VerifyAddresses.tsx @@ -149,15 +149,20 @@ export const VerifyAddresses = () => { accountMetadata: sellAccountMetadata, pubKey: fromAccountId(sellAssetAccountId).account, }) - const fetchedOrManualBuyAddress = shouldVerifyBuyAddress - ? await getReceiveAddress({ - asset: buyAsset, - wallet, - deviceId, - accountMetadata: buyAccountMetadata!, - pubKey: fromAccountId(buyAssetAccountId!).account, - }) - : maybeManualReceiveAddress + + const fetchedOrManualBuyAddress = await (() => { + if (!shouldVerifyBuyAddress) return maybeManualReceiveAddress + + if (!buyAssetAccountId || !buyAccountMetadata) throw new Error('Missing buy account metadata') + + return getReceiveAddress({ + asset: buyAsset, + wallet, + deviceId, + accountMetadata: buyAccountMetadata, + pubKey: fromAccountId(buyAssetAccountId).account, + }) + })() setSellAddress(fetchedSellAddress) setBuyAddress(fetchedOrManualBuyAddress) diff --git a/src/components/MultiHopTrade/hooks/useInputOutputDifference.ts b/src/components/MultiHopTrade/hooks/useInputOutputDifference.ts index bd0fe30e282..e08b78f42a0 100644 --- a/src/components/MultiHopTrade/hooks/useInputOutputDifference.ts +++ b/src/components/MultiHopTrade/hooks/useInputOutputDifference.ts @@ -24,12 +24,12 @@ export const useInputOutputDifferenceDecimalPercentage = ( if (!tradeQuote || !sellAsset || !sellAssetUsdRate) return // A quote always has a first hop - const firstHop = getHopByIndex(tradeQuote, 0)! + const firstHop = getHopByIndex(tradeQuote, 0) const sellAmountIncludingProtocolFeesCryptoBaseUnit = - firstHop.sellAmountIncludingProtocolFeesCryptoBaseUnit + firstHop?.sellAmountIncludingProtocolFeesCryptoBaseUnit const sellAmountIncludingProtocolFeesCryptoPrecision = fromBaseUnit( - sellAmountIncludingProtocolFeesCryptoBaseUnit, + sellAmountIncludingProtocolFeesCryptoBaseUnit ?? '0', sellAsset.precision, ) @@ -41,11 +41,11 @@ export const useInputOutputDifferenceDecimalPercentage = ( const lastHopIndex = (numSteps - 1) as SupportedTradeQuoteStepIndex // A quote always has a last hop since it always has a first hop - const lastHop = getHopByIndex(tradeQuote, lastHopIndex)! - const buyAmountAfterProtocolFeesCryptoBaseUnit = lastHop.buyAmountAfterFeesCryptoBaseUnit + const lastHop = getHopByIndex(tradeQuote, lastHopIndex) + const buyAmountAfterProtocolFeesCryptoBaseUnit = lastHop?.buyAmountAfterFeesCryptoBaseUnit const buyAmountAfterProtocolFeesCryptoPrecision = fromBaseUnit( - buyAmountAfterProtocolFeesCryptoBaseUnit, + buyAmountAfterProtocolFeesCryptoBaseUnit ?? '0', buyAsset.precision, ) diff --git a/src/react-queries/hooks/useQuoteEstimatedFeesQuery.ts b/src/react-queries/hooks/useQuoteEstimatedFeesQuery.ts index 8d65434e9fc..34eb1c00839 100644 --- a/src/react-queries/hooks/useQuoteEstimatedFeesQuery.ts +++ b/src/react-queries/hooks/useQuoteEstimatedFeesQuery.ts @@ -1,7 +1,7 @@ import type { AccountId, AssetId } from '@shapeshiftoss/caip' import { fromAssetId } from '@shapeshiftoss/caip' import type { Asset, KnownChainIds } from '@shapeshiftoss/types' -import { useQuery } from '@tanstack/react-query' +import { skipToken, useQuery } from '@tanstack/react-query' import { useMemo } from 'react' import { toHex } from 'viem' import { estimateFees } from 'components/Modals/Send/utils' @@ -111,7 +111,6 @@ export const useQuoteEstimatedFeesQuery = ({ collateralAccountId, ]) - // TODO(gomes): this is wrong, we should use a proper generated query for this const quoteEstimatedFeesQueryKey = useMemo( () => ['thorchainLendingQuoteEstimatedFees', estimateFeesArgs], [estimateFeesArgs], @@ -139,15 +138,17 @@ export const useQuoteEstimatedFeesQuery = ({ const useQuoteEstimatedFeesQuery = useQuery({ queryKey: quoteEstimatedFeesQueryKey, - queryFn: async () => { - const estimatedFees = await estimateFees(estimateFeesArgs) - const txFeeFiat = bnOrZero(estimatedFees.fast.txFee) - .div(bn(10).pow(feeAsset!.precision)) // actually defined at runtime, see "enabled" below - .times(feeAssetMarketData.price) - .toString() - return { estimatedFees, txFeeFiat, txFeeCryptoBaseUnit: estimatedFees.fast.txFee } - }, - enabled, + queryFn: + enabled && feeAsset + ? async () => { + const estimatedFees = await estimateFees(estimateFeesArgs) + const txFeeFiat = bnOrZero(estimatedFees.fast.txFee) + .div(bn(10).pow(feeAsset.precision)) + .times(feeAssetMarketData.price) + .toString() + return { estimatedFees, txFeeFiat, txFeeCryptoBaseUnit: estimatedFees.fast.txFee } + } + : skipToken, retry: false, }) From 4ea47a3632fc81af03c3769a77f7e77a42c8384f Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Fri, 21 Feb 2025 15:42:21 +0100 Subject: [PATCH 12/13] feat: re-comment --- .eslintrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.eslintrc b/.eslintrc index b591c375e56..5046fae8852 100644 --- a/.eslintrc +++ b/.eslintrc @@ -97,8 +97,8 @@ "react/jsx-handler-names": "error", "require-await": "error", "import/no-duplicates": "error", - "react-memo/require-usememo": "error", - "@typescript-eslint/no-non-null-assertion": "warn" + "react-memo/require-usememo": "error" + // "@typescript-eslint/no-non-null-assertion": "warn" }, "overrides": [ { From 6b83bbb5d0d811d3f663342133093fb3a717359d Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Thu, 6 Mar 2025 16:04:37 +0300 Subject: [PATCH 13/13] feat: cleanup --- headers/types.ts | 6 +++--- headers/util.ts | 7 +------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/headers/types.ts b/headers/types.ts index e92c32b0132..084034fcb8d 100644 --- a/headers/types.ts +++ b/headers/types.ts @@ -1,3 +1,3 @@ -// process.env is not properly typed but could be if we were using vite imports.meta. wen vite? -export type Csp = Record -export type CspEntry = (string | undefined)[] +// TODO: process.env is not properly typed but can now be with vite https://vite.dev/guide/env-and-mode +export type Csp = Record +export type CspEntry = string[] diff --git a/headers/util.ts b/headers/util.ts index 9d2e2af2146..8ccbeaa106f 100644 --- a/headers/util.ts +++ b/headers/util.ts @@ -6,7 +6,7 @@ import type { Csp, CspEntry } from './types' export function cspToEntries(x: Csp): CspEntry[] { return Object.entries(x).flatMap(([k, v]) => { return v.map(entry => { - const out = [k, entry] + const out: [string, string] = [k, entry] return out }) }) @@ -21,9 +21,6 @@ export function entriesToCsp(x: CspEntry[]): Csp { const acc: Csp = {} return x .sort(([k1, v1], [k2, v2]) => { - if (k1 === undefined || k2 === undefined) return 0 - if (v1 === undefined || v2 === undefined) return 0 - if (k1 < k2) return -1 if (k1 > k2) return 1 if (v1 < v2) return -1 @@ -31,8 +28,6 @@ export function entriesToCsp(x: CspEntry[]): Csp { return 0 }) .reduce((a, [k, v]) => { - if (!k) return a - a[k] ??= [] if (v && (a[k].length === 0 || v !== "'none'") && !a[k].includes(v)) a[k].push(v) if (a[k].length > 1) a[k] = a[k].filter(x => x !== "'none'")