From 7e70cf6acc5f1620286b5569e0ae218567a534d6 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Mon, 2 Oct 2023 17:31:55 +0200 Subject: [PATCH 01/10] feat: bnb savers (#5383) --- .../opportunitiesSlice/resolvers/thorchainsavers/utils.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/utils.ts b/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/utils.ts index 98353c7f9af..8c8fdb5b794 100644 --- a/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/utils.ts +++ b/src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/utils.ts @@ -3,6 +3,7 @@ import { avalancheAssetId, bchAssetId, binanceAssetId, + bscAssetId, btcAssetId, cosmosAssetId, dogeAssetId, @@ -62,6 +63,7 @@ export const THORCHAIN_SAVERS_DUST_THRESHOLDS = { [dogeAssetId]: '100000000', [ethAssetId]: '10000000000', [avalancheAssetId]: '10000000000', + [bscAssetId]: '10000000000', [cosmosAssetId]: '0', [binanceAssetId]: '0', [usdcEthereumAssetId]: '0', @@ -73,6 +75,7 @@ const SUPPORTED_THORCHAIN_SAVERS_ASSET_IDS = [ cosmosAssetId, avalancheAssetId, ethAssetId, + bscAssetId, btcAssetId, bchAssetId, ltcAssetId, From 8beb2738e8026698c66a3c957b9cb0352e7ca4d6 Mon Sep 17 00:00:00 2001 From: 0xdef1cafe <88504456+0xdef1cafe@users.noreply.github.com> Date: Tue, 3 Oct 2023 11:20:41 +1100 Subject: [PATCH 02/10] feat: plotly interactive chart thing (#5375) Co-authored-by: reallybeard <89934888+reallybeard@users.noreply.github.com> --- .env.base | 1 + .env.dev | 3 +- package.json | 1 + src/components/FeeExplainer/FeeExplainer.tsx | 369 ++++++++++++++++++ .../FeeExplainer/components/FeeInput.tsx | 69 ++++ src/config.ts | 1 + src/lib/fees/model.test.ts | 28 +- src/lib/fees/model.ts | 39 +- src/pages/Trade/Trade.tsx | 5 +- .../preferencesSlice/preferencesSlice.ts | 2 + src/test/mocks/store.ts | 1 + yarn.lock | 18 + 12 files changed, 514 insertions(+), 23 deletions(-) create mode 100644 src/components/FeeExplainer/FeeExplainer.tsx create mode 100644 src/components/FeeExplainer/components/FeeInput.tsx diff --git a/.env.base b/.env.base index a900fe1c716..b02e21f17ce 100644 --- a/.env.base +++ b/.env.base @@ -24,6 +24,7 @@ REACT_APP_FEATURE_CHATWOOT=false REACT_APP_FEATURE_COINBASE_WALLET=true REACT_APP_FEATURE_ADVANCED_SLIPPAGE=true REACT_APP_FEATURE_WALLET_CONNECT_V2=false +REACT_APP_FEATURE_FOX_DISCOUNTS=false # absolute URL prefix REACT_APP_ABSOLUTE_URL_PREFIX=https://app.shapeshift.com diff --git a/.env.dev b/.env.dev index e379379fb27..6390ddd9516 100644 --- a/.env.dev +++ b/.env.dev @@ -1,6 +1,7 @@ # feature flags REACT_APP_FEATURE_NFT_METADATA=true REACT_APP_FEATURE_WALLET_CONNECT_V2=true +REACT_APP_FEATURE_FOX_DISCOUNTS=true # logging REACT_APP_REDUX_WINDOW=false @@ -46,4 +47,4 @@ REACT_APP_COSMOS_NODE_URL=https://dev-daemon.cosmos.shapeshift.com REACT_APP_THORCHAIN_NODE_URL=https://dev-daemon.thorchain.shapeshift.com # thorchain -REACT_APP_MIDGARD_URL=https://dev-indexer.thorchain.shapeshift.com/v2 \ No newline at end of file +REACT_APP_MIDGARD_URL=https://dev-indexer.thorchain.shapeshift.com/v2 diff --git a/package.json b/package.json index 375566bb7ae..09759e78d4a 100644 --- a/package.json +++ b/package.json @@ -109,6 +109,7 @@ "@snapshot-labs/snapshot.js": "^0.6.1", "@sniptt/monads": "^0.5.10", "@types/bip21": "^2.0.0", + "@types/react-plotly.js": "^2.6.0", "@uniswap/sdk": "^3.0.3", "@unstoppabledomains/resolution": "^8.3.3", "@visx/gradient": "^2.10.0", diff --git a/src/components/FeeExplainer/FeeExplainer.tsx b/src/components/FeeExplainer/FeeExplainer.tsx new file mode 100644 index 00000000000..50ac269631e --- /dev/null +++ b/src/components/FeeExplainer/FeeExplainer.tsx @@ -0,0 +1,369 @@ +import { + Box, + Card, + CardBody, + Flex, + Heading, + Slider, + SliderFilledTrack, + SliderMark, + SliderThumb, + SliderTrack, + Stack, + Text, + useToken, + VStack, +} from '@chakra-ui/react' +import { LinearGradient } from '@visx/gradient' +import { ScaleSVG } from '@visx/responsive' +import type { GlyphProps } from '@visx/xychart' +import { + AnimatedAreaSeries, + AnimatedAxis, + AnimatedGlyphSeries, + Tooltip, + XYChart, +} from '@visx/xychart' +import type { RenderTooltipParams } from '@visx/xychart/lib/components/Tooltip' +import debounce from 'lodash/debounce' +import { useCallback, useEffect, useMemo, useState } from 'react' +import { Amount } from 'components/Amount/Amount' +import { RawText } from 'components/Text' +import { bn } from 'lib/bignumber/bignumber' +import { calculateFees } from 'lib/fees/model' +import { FEE_CURVE_MAX_FEE_BPS, FEE_CURVE_NO_FEE_THRESHOLD_USD } from 'lib/fees/parameters' +import { isSome } from 'lib/utils' +import { useGetVotingPowerQuery } from 'state/apis/snapshot/snapshot' +import { selectWalletAccountIds } from 'state/slices/common-selectors' +import { useAppSelector } from 'state/store' + +type FeeChartProps = { + tradeSize: number + foxHolding: number + onHover(hoverTradeSize: number, hoverFoxHolding: number): void +} + +// how many points to generate for the chart, higher is more accurate but slower +const CHART_GRANULARITY = 100 +const CHART_TRADE_SIZE_MAX_USD = 400_000 +const CHART_TRADE_SIZE_MAX_FOX = 1_100_000 // let them go a bit past a million + +// Generate data for tradeSize and foxHolding +const tradeSizeData = [...Array(CHART_GRANULARITY).keys()].map( + i => i * (CHART_TRADE_SIZE_MAX_USD / (CHART_GRANULARITY - 1)), +) + +const accessors = { + xAccessor: ({ x }: { x: number }) => x, + yAccessor: ({ y }: { y: number }) => y, +} + +type ChartData = { + x: number + y: number +} + +const renderTooltip = ({ tooltipData }: RenderTooltipParams) => { + return ( +
+ Trade Size: {tooltipData?.nearestDatum?.datum?.x}
+ Fee (bps): {tooltipData?.nearestDatum?.datum?.y} +
+ ) +} + +const formatMetricSuffix = (num: number) => { + if (Math.abs(num) >= 1e6) return `${(Math.abs(num) / 1e6).toFixed(0)}M` + if (Math.abs(num) >= 1e3) return `${(Math.abs(num) / 1e3).toFixed(0)}K` + return `${Math.abs(num)}` +} + +const foxBlue = '#3761F9' + +const lineProps = { + stroke: foxBlue, +} + +const xScale = { type: 'linear' as const } +const yScale = { type: 'linear' as const, domain: [0, FEE_CURVE_MAX_FEE_BPS] } + +const FeeChart: React.FC = ({ foxHolding, tradeSize }) => { + const width = 450 + const height = 250 + const textColor = useToken('colors', 'text.subtle') + const borderColor = useToken('colors', 'border.base') + const circleBg = useToken('colors', 'blue.500') + const circleStroke = useToken('colors', 'text.base') + + const [debouncedFoxHolding, setDebouncedFoxHolding] = useState(foxHolding) + + const DEBOUNCE_MS = 150 // tune me to make the curve changing shape "feel" right + + // Debounce foxHolding updates + useEffect(() => { + const handleDebounce = debounce(() => setDebouncedFoxHolding(foxHolding), DEBOUNCE_MS) + handleDebounce() + + return handleDebounce.cancel + }, [foxHolding]) + + const data = useMemo(() => { + return tradeSizeData + .map(trade => { + if (trade < FEE_CURVE_NO_FEE_THRESHOLD_USD) return null + const feeBps = calculateFees({ + tradeAmountUsd: bn(trade), + foxHeld: bn(debouncedFoxHolding), + }).feeBps.toNumber() + return { x: trade, y: feeBps } + }) + .filter(isSome) + }, [debouncedFoxHolding]) + + const currentPoint = useMemo(() => { + if (tradeSize < FEE_CURVE_NO_FEE_THRESHOLD_USD) return [] + + const feeBps = calculateFees({ + tradeAmountUsd: bn(tradeSize), + foxHeld: bn(debouncedFoxHolding), + }).feeBps.toNumber() + + return [{ x: tradeSize, y: feeBps }] + }, [tradeSize, debouncedFoxHolding]) + + const tickLabelProps = useCallback( + () => ({ fill: textColor, fontSize: 12, fontWeight: 'medium' }), + [textColor], + ) + + const tickFormat = useCallback((x: number) => `$${formatMetricSuffix(x)}`, []) + + const labelProps = useCallback((fill: string) => ({ fill, fontSize: 12, fontWeight: 'bold' }), []) + + const renderGlyph = useCallback( + ({ x, y }: GlyphProps<{ x: number; y: number }>) => ( + + ), + [circleBg, circleStroke], + ) + + return ( + + + + + + + + + + + + + + ) +} + +type FeeSlidersProps = { + tradeSize: number + setTradeSize: (val: number) => void + foxHolding: number + setFoxHolding: (val: number) => void + currentFoxHoldings: string +} + +const labelStyles = { + fontSize: 'sm', + mt: '2', + ml: '-2.5', + color: 'text.subtle', +} + +const FeeSliders: React.FC = ({ + tradeSize, + setTradeSize, + foxHolding, + setFoxHolding, +}) => { + return ( + + + + Trade Size + + + + + + + + + + + + + + + + + + + + + + + FOX Holding + + + + + + + + + + 250k + + + 500k + + + 750k + + + 1MM + + + + + + ) +} + +type FeeOutputProps = { + tradeSize: number + foxHolding: number +} + +export const FeeOutput: React.FC = ({ tradeSize, foxHolding }) => { + const { feeBps, feeUsd, foxDiscountPercent } = calculateFees({ + tradeAmountUsd: bn(tradeSize), + foxHeld: bn(foxHolding), + }) + return ( + + + + + {feeUsd.lte(0) ? ( + + Free + + ) : ( + + )} + Total Fees + + + + + + FOX Holder Discount + + + + + Fee before discount: ${feeUsd.toFixed(2)} ({feeBps.toFixed(2)} bps) + + + ) +} + +const feeExplainerCardBody = { base: 4, md: 8 } + +export const FeeExplainer = () => { + const [tradeSize, setTradeSize] = useState(0) + const [foxHolding, setFoxHolding] = useState(0) + + const walletAccountIds = useAppSelector(selectWalletAccountIds) + const { data: currentFoxHoldings } = useGetVotingPowerQuery(walletAccountIds) + const onHover = (hoverTradeSize: number, hoverFoxHolding: number) => { + setTradeSize(hoverTradeSize) + setFoxHolding(hoverFoxHolding) + } + + return ( + + + Calculate your FOX Savings + + Something about savings, put good copy in here that doesn't suck. + + FOX voting power {currentFoxHoldings} FOX + + + + + + + + + + ) +} diff --git a/src/components/FeeExplainer/components/FeeInput.tsx b/src/components/FeeExplainer/components/FeeInput.tsx new file mode 100644 index 00000000000..eb3a20853a2 --- /dev/null +++ b/src/components/FeeExplainer/components/FeeInput.tsx @@ -0,0 +1,69 @@ +import type { InputProps } from '@chakra-ui/react' +import { Input } from '@chakra-ui/react' +import { useCallback, useRef } from 'react' +import type { NumberFormatValues } from 'react-number-format' +import NumberFormat from 'react-number-format' +import { useTranslate } from 'react-polyglot' +import { useLocaleFormatter } from 'hooks/useLocaleFormatter/useLocaleFormatter' + +const CryptoInput = (props: InputProps) => { + const translate = useTranslate() + return ( + + ) +} + +type FeeInputProps = { + isFiat?: boolean + onChange?: (value: string, isFiat?: boolean) => void + value?: string | number | null +} + +const numberFormatDisabled = { opacity: 1, cursor: 'not-allowed' } + +export const FeeInput: React.FC = ({ isFiat, onChange, value }) => { + const amountRef = useRef(null) + const { + number: { localeParts }, + } = useLocaleFormatter() + + const handleOnChange = useCallback(() => { + // onChange will send us the formatted value + // To get around this we need to get the value from the onChange using a ref + // Now when the max buttons are clicked the onChange will not fire + onChange?.(amountRef.current ?? '', isFiat) + }, [isFiat, onChange]) + + const handleValueChange = useCallback((values: NumberFormatValues) => { + // This fires anytime value changes including setting it on max click + // Store the value in a ref to send when we actually want the onChange to fire + amountRef.current = values.value + }, []) + return ( + + ) +} diff --git a/src/config.ts b/src/config.ts index bfa806d4c65..6b3527f32e3 100644 --- a/src/config.ts +++ b/src/config.ts @@ -146,6 +146,7 @@ const validators = { REACT_APP_EXPERIMENTAL_CUSTOM_SEND_NONCE: bool({ default: false }), REACT_APP_EXPERIMENTAL_MM_SNAPPY_FINGERS: bool({ default: false }), REACT_APP_SNAP_ID: str(), + REACT_APP_FEATURE_FOX_DISCOUNTS: bool({ default: false }), } function reporter({ errors }: envalid.ReporterOptions) { diff --git a/src/lib/fees/model.test.ts b/src/lib/fees/model.test.ts index 7d405d0954e..bfae6b0d554 100644 --- a/src/lib/fees/model.test.ts +++ b/src/lib/fees/model.test.ts @@ -1,6 +1,6 @@ import { bn } from 'lib/bignumber/bignumber' -import { calculateFeeBps } from './model' +import { calculateFees } from './model' import { FEE_CURVE_FOX_MAX_DISCOUNT_THRESHOLD, FEE_CURVE_MIDPOINT_USD, @@ -11,60 +11,62 @@ describe('calculateFees', () => { it('should return 0 bps for <= no fee threshold', () => { const tradeAmountUsd = bn(FEE_CURVE_NO_FEE_THRESHOLD_USD) const foxHeld = bn(0) - const bps = calculateFeeBps({ + const { feeBps } = calculateFees({ tradeAmountUsd, foxHeld, }) - expect(bps.toNumber()).toEqual(0) + expect(feeBps.toNumber()).toEqual(0) }) it('should return close to max bps for slightly above no fee threshold', () => { const tradeAmountUsd = bn(FEE_CURVE_NO_FEE_THRESHOLD_USD + 0.01) const foxHeld = bn(0) - const bps = calculateFeeBps({ + const { feeBps } = calculateFees({ tradeAmountUsd, foxHeld, }) - expect(bps.toNumber()).toEqual(28.552638258646432) + expect(feeBps.toNumber()).toEqual(28.552638258646432) }) it('should return close to min bps for huge amounts', () => { const tradeAmountUsd = bn(1_000_000) const foxHeld = bn(0) - const bps = calculateFeeBps({ + const { feeBps } = calculateFees({ tradeAmountUsd, foxHeld, }) - expect(bps.toNumber()).toEqual(10.000000011220077) + expect(feeBps.toNumber()).toEqual(10.000000011220077) }) it('should return close to midpoint for midpoint', () => { const tradeAmountUsd = bn(FEE_CURVE_MIDPOINT_USD) const foxHeld = bn(0) - const bps = calculateFeeBps({ + const { feeBps } = calculateFees({ tradeAmountUsd, foxHeld, }) - expect(bps.toNumber()).toEqual(19.5) + expect(feeBps.toNumber()).toEqual(19.5) }) it('should discount fees by 50% holding at midpoint holding half max fox discount limit', () => { const tradeAmountUsd = bn(FEE_CURVE_MIDPOINT_USD) const foxHeld = bn(FEE_CURVE_FOX_MAX_DISCOUNT_THRESHOLD / 2) - const bps = calculateFeeBps({ + const { feeBps, foxDiscountPercent } = calculateFees({ tradeAmountUsd, foxHeld, }) - expect(bps.toNumber()).toEqual(9.75) + expect(feeBps.toNumber()).toEqual(9.75) + expect(foxDiscountPercent).toEqual(bn(50)) }) it('should discount fees 100% holding max fox discount limit', () => { const tradeAmountUsd = bn(Infinity) const foxHeld = bn(FEE_CURVE_FOX_MAX_DISCOUNT_THRESHOLD) - const bps = calculateFeeBps({ + const { feeBps, foxDiscountPercent } = calculateFees({ tradeAmountUsd, foxHeld, }) - expect(bps.toNumber()).toEqual(0) + expect(feeBps.toNumber()).toEqual(0) + expect(foxDiscountPercent).toEqual(bn(100)) }) }) diff --git a/src/lib/fees/model.ts b/src/lib/fees/model.ts index 55192fc8000..461ef7d2e15 100644 --- a/src/lib/fees/model.ts +++ b/src/lib/fees/model.ts @@ -15,17 +15,36 @@ type CalculateFeeBpsArgs = { foxHeld: BigNumber } -type CalculateFeeBps = (args: CalculateFeeBpsArgs) => BigNumber +type CalculateFeeBpsReturn = { + feeBps: BigNumber + feeUsd: BigNumber + feeUsdDiscount: BigNumber + foxDiscountPercent: BigNumber +} +type CalculateFeeBps = (args: CalculateFeeBpsArgs) => CalculateFeeBpsReturn -export const calculateFeeBps: CalculateFeeBps = ({ tradeAmountUsd, foxHeld }): BigNumber => { +export const calculateFees: CalculateFeeBps = ({ tradeAmountUsd, foxHeld }) => { const noFeeThresholdUsd = bn(FEE_CURVE_NO_FEE_THRESHOLD_USD) const maxFeeBps = bn(FEE_CURVE_MAX_FEE_BPS) const minFeeBps = bn(FEE_CURVE_MIN_FEE_BPS) const midpointUsd = bn(FEE_CURVE_MIDPOINT_USD) const feeCurveSteepness = bn(FEE_CURVE_STEEPNESS_K) - if (tradeAmountUsd.lte(noFeeThresholdUsd)) return bn(0) - const sigmoidFee = minFeeBps.plus( + const foxDiscountPercent = BigNumber.minimum( + bn(100), + foxHeld.times(100).div(bn(FEE_CURVE_FOX_MAX_DISCOUNT_THRESHOLD)), + ) + + if (tradeAmountUsd.lte(noFeeThresholdUsd)) { + return { + feeBps: bn(0), + feeUsd: bn(0), + feeUsdDiscount: bn(0), + foxDiscountPercent, + } + } + + const feeBpsBeforeDiscount = minFeeBps.plus( maxFeeBps .minus(minFeeBps) .div( @@ -39,9 +58,13 @@ export const calculateFeeBps: CalculateFeeBps = ({ tradeAmountUsd, foxHeld }): B ), ) - const foxDiscount = foxHeld.div(bn(FEE_CURVE_FOX_MAX_DISCOUNT_THRESHOLD)) - - const feeBps = sigmoidFee.multipliedBy(bn(1).minus(foxDiscount)) + const feeBps = BigNumber.maximum( + feeBpsBeforeDiscount.multipliedBy(bn(1).minus(foxDiscountPercent.div(100))), + bn(0), + ) + const feeUsdBeforeDiscount = tradeAmountUsd.multipliedBy(feeBpsBeforeDiscount.div(bn(10000))) + const feeUsdDiscount = feeUsdBeforeDiscount.multipliedBy(foxDiscountPercent.div(100)) + const feeUsd = feeUsdBeforeDiscount.minus(feeUsdDiscount) - return BigNumber.maximum(feeBps, bn(0)) + return { feeBps, feeUsd, feeUsdDiscount, foxDiscountPercent } } diff --git a/src/pages/Trade/Trade.tsx b/src/pages/Trade/Trade.tsx index 2b68b26f77e..a872b1fff10 100644 --- a/src/pages/Trade/Trade.tsx +++ b/src/pages/Trade/Trade.tsx @@ -1,20 +1,23 @@ import { Container, Stack } from '@chakra-ui/react' import { memo } from 'react' +import { FeeExplainer } from 'components/FeeExplainer/FeeExplainer' import { Main } from 'components/Layout/Main' import { MultiHopTrade } from 'components/MultiHopTrade/MultiHopTrade' +import { useFeatureFlag } from 'hooks/useFeatureFlag/useFeatureFlag' import { RecentTransactions } from 'pages/Dashboard/RecentTransactions' const maxWidth = { base: '100%', lg: 'container.sm' } const padding = { base: 0, md: 8 } export const Trade = memo(() => { + const foxDiscountsEnabled = useFeatureFlag('FoxDiscounts') return (
- + {foxDiscountsEnabled && } diff --git a/src/state/slices/preferencesSlice/preferencesSlice.ts b/src/state/slices/preferencesSlice/preferencesSlice.ts index 8207af5f713..8873daf31a8 100644 --- a/src/state/slices/preferencesSlice/preferencesSlice.ts +++ b/src/state/slices/preferencesSlice/preferencesSlice.ts @@ -44,6 +44,7 @@ export type FeatureFlags = { WalletConnectV2: boolean CustomSendNonce: boolean Snaps: boolean + FoxDiscounts: boolean } export type Flag = keyof FeatureFlags @@ -105,6 +106,7 @@ const initialState: Preferences = { WalletConnectV2: getConfig().REACT_APP_FEATURE_WALLET_CONNECT_V2, CustomSendNonce: getConfig().REACT_APP_EXPERIMENTAL_CUSTOM_SEND_NONCE, Snaps: getConfig().REACT_APP_EXPERIMENTAL_MM_SNAPPY_FINGERS, + FoxDiscounts: getConfig().REACT_APP_FEATURE_FOX_DISCOUNTS, }, selectedLocale: simpleLocale(), balanceThreshold: '0', diff --git a/src/test/mocks/store.ts b/src/test/mocks/store.ts index 70e6a8001ba..490e27e6e2d 100644 --- a/src/test/mocks/store.ts +++ b/src/test/mocks/store.ts @@ -92,6 +92,7 @@ export const mockStore: ReduxState = { WalletConnectV2: false, CustomSendNonce: false, Snaps: false, + FoxDiscounts: false, }, selectedLocale: 'en', balanceThreshold: '0', diff --git a/yarn.lock b/yarn.lock index ba1aed1b319..eea8810b563 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8230,6 +8230,7 @@ __metadata: "@types/react-datepicker": ^4.4.2 "@types/react-dom": ^18.0.5 "@types/react-infinite-scroller": ^1.2.3 + "@types/react-plotly.js": ^2.6.0 "@types/react-redux": ^7.1.24 "@types/react-router-dom": ^5.3.2 "@types/react-table": ^7.7.12 @@ -9738,6 +9739,13 @@ __metadata: languageName: node linkType: hard +"@types/plotly.js@npm:*": + version: 2.12.27 + resolution: "@types/plotly.js@npm:2.12.27" + checksum: f59c27a2b86ccfe680bd0441e84b59d5281dcc74ae9a90f88d51429b8885c2fb9cbf0e7144fc963ad1230a9ac1b7c156e7a6375cde2cf8332159a05e234b66e5 + languageName: node + linkType: hard + "@types/pngjs@npm:^6.0.1": version: 6.0.1 resolution: "@types/pngjs@npm:6.0.1" @@ -9821,6 +9829,16 @@ __metadata: languageName: node linkType: hard +"@types/react-plotly.js@npm:^2.6.0": + version: 2.6.0 + resolution: "@types/react-plotly.js@npm:2.6.0" + dependencies: + "@types/plotly.js": "*" + "@types/react": "*" + checksum: 91ab4eb8f1ab68add2884f01419884ce9746121681e6c9e883c8ce26e9a549108bf61cdeb2008b64bd1886934d4ac106af4c3c61d1d159e13236b4a1858e6ea8 + languageName: node + linkType: hard + "@types/react-redux@npm:^7.1.20, @types/react-redux@npm:^7.1.24": version: 7.1.24 resolution: "@types/react-redux@npm:7.1.24" From 77408efd5213cb0ed640baa9039f92f5daaa1837 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Tue, 3 Oct 2023 02:52:23 +0200 Subject: [PATCH 03/10] fix(cowSwapper): don't convert orderDigest to Uint8Array / hex (#5382) * fix(cowSwapper): don't convert orderDigest to Uint8Array / hex * feat: improve types and safety * feat: consume verdaccio packages * feat: rm TODO * chore: update dependencies --------- Co-authored-by: Apotheosis <97164662+0xApotheosis@users.noreply.github.com> --- package.json | 22 +- .../useTradeExecution/useTradeExecution.ts | 2 +- .../swapper/swappers/CowSwapper/CowSwapper.ts | 7 +- src/lib/swapper/types.ts | 2 +- yarn.lock | 230 +++++++++--------- 5 files changed, 133 insertions(+), 130 deletions(-) diff --git a/package.json b/package.json index 09759e78d4a..d74c463dfc0 100644 --- a/package.json +++ b/package.json @@ -93,17 +93,17 @@ "@shapeshiftoss/caip": "workspace:^", "@shapeshiftoss/chain-adapters": "workspace:^", "@shapeshiftoss/errors": "workspace:^", - "@shapeshiftoss/hdwallet-coinbase": "^1.50.4", - "@shapeshiftoss/hdwallet-core": "^1.50.4", - "@shapeshiftoss/hdwallet-keepkey": "^1.50.4", - "@shapeshiftoss/hdwallet-keepkey-webusb": "^1.50.4", - "@shapeshiftoss/hdwallet-keplr": "^1.50.4", - "@shapeshiftoss/hdwallet-metamask": "^1.50.4", - "@shapeshiftoss/hdwallet-native": "^1.50.4", - "@shapeshiftoss/hdwallet-native-vault": "^1.50.4", - "@shapeshiftoss/hdwallet-shapeshift-multichain": "^1.50.5-alpha.70", - "@shapeshiftoss/hdwallet-walletconnectv2": "1.50.8", - "@shapeshiftoss/hdwallet-xdefi": "^1.50.4", + "@shapeshiftoss/hdwallet-coinbase": "1.51.0", + "@shapeshiftoss/hdwallet-core": "1.51.0", + "@shapeshiftoss/hdwallet-keepkey": "1.51.0", + "@shapeshiftoss/hdwallet-keepkey-webusb": "1.51.0", + "@shapeshiftoss/hdwallet-keplr": "1.51.0", + "@shapeshiftoss/hdwallet-metamask": "1.51.0", + "@shapeshiftoss/hdwallet-native": "1.51.0", + "@shapeshiftoss/hdwallet-native-vault": "1.51.0", + "@shapeshiftoss/hdwallet-shapeshift-multichain": "1.51.0", + "@shapeshiftoss/hdwallet-walletconnectv2": "1.51.0", + "@shapeshiftoss/hdwallet-xdefi": "1.51.0", "@shapeshiftoss/types": "workspace:^", "@shapeshiftoss/unchained-client": "workspace:^", "@snapshot-labs/snapshot.js": "^0.6.1", diff --git a/src/components/MultiHopTrade/hooks/useTradeExecution/useTradeExecution.ts b/src/components/MultiHopTrade/hooks/useTradeExecution/useTradeExecution.ts index 60632f15519..083afe4f1eb 100644 --- a/src/components/MultiHopTrade/hooks/useTradeExecution/useTradeExecution.ts +++ b/src/components/MultiHopTrade/hooks/useTradeExecution/useTradeExecution.ts @@ -114,7 +114,7 @@ export const useTradeExecution = ({ stepIndex: activeStepOrDefault, slippageTolerancePercentageDecimal, from, - signMessage: async (message: Uint8Array) => { + signMessage: async (message: string) => { const messageToSign: ETHSignMessage = { addressNList: toAddressNList(bip44Params), message, diff --git a/src/lib/swapper/swappers/CowSwapper/CowSwapper.ts b/src/lib/swapper/swappers/CowSwapper/CowSwapper.ts index 3ea29bdead0..96871333f45 100644 --- a/src/lib/swapper/swappers/CowSwapper/CowSwapper.ts +++ b/src/lib/swapper/swappers/CowSwapper/CowSwapper.ts @@ -1,6 +1,7 @@ import { type AssetId, fromChainId } from '@shapeshiftoss/caip' import { getConfig } from 'config' import { ethers } from 'ethers' +import { isHexString } from 'ethers/lib/utils.js' import type { Asset } from 'lib/asset-service' import type { BuyAssetBySellIdInput, @@ -27,7 +28,11 @@ export const cowSwapper: Swapper = { // Some context about this : https://docs.cow.fi/tutorials/how-to-submit-orders-via-the-api/4.-signing-the-order // For more info, check hashOrder method implementation const orderDigest = hashOrder(domain(signingDomain, COW_SWAP_SETTLEMENT_ADDRESS), orderToSign) - const messageToSign = ethers.utils.arrayify(orderDigest) + // orderDigest should be an hex string here. All we need to do is pass it to signMessage/wallet.ethSignMessage and sign it + const messageToSign = orderDigest + + if (!isHexString(messageToSign)) throw new Error('messageToSign is not an hex string') + const signatureOrderDigest = await signMessage(messageToSign) // Passing the signature through split/join to normalize the `v` byte. diff --git a/src/lib/swapper/types.ts b/src/lib/swapper/types.ts index 48144435701..48f90ddbaae 100644 --- a/src/lib/swapper/types.ts +++ b/src/lib/swapper/types.ts @@ -181,7 +181,7 @@ export type EvmTransactionExecutionProps = { } export type EvmMessageExecutionProps = { - signMessage: (messageToSign: Uint8Array) => Promise + signMessage: (messageToSign: string) => Promise } export type UtxoTransactionExecutionProps = { diff --git a/yarn.lock b/yarn.lock index eea8810b563..9092ca47d13 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6729,17 +6729,7 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-ui@npm:1.0.1": - version: 1.0.1 - resolution: "@metamask/snaps-ui@npm:1.0.1" - dependencies: - "@metamask/utils": ^6.0.1 - superstruct: ^1.0.3 - checksum: 71719b47a79d2ff23f0e9f1d2a1a8afd42f4f94891437056241a49090d245ccd086eac5d8fdf7719aaaa3f6bbc16b30f5566ad7bcecaa7b70e00ea638387aaa0 - languageName: node - linkType: hard - -"@metamask/snaps-ui@npm:^1.0.1, @metamask/snaps-ui@npm:^1.0.2": +"@metamask/snaps-ui@npm:1.0.2, @metamask/snaps-ui@npm:^1.0.1, @metamask/snaps-ui@npm:^1.0.2": version: 1.0.2 resolution: "@metamask/snaps-ui@npm:1.0.2" dependencies: @@ -7717,7 +7707,7 @@ __metadata: languageName: node linkType: hard -"@shapeshiftoss/caip@^8.15.0, @shapeshiftoss/caip@workspace:^, @shapeshiftoss/caip@workspace:packages/caip": +"@shapeshiftoss/caip@8.15.0, @shapeshiftoss/caip@^8.15.0, @shapeshiftoss/caip@workspace:^, @shapeshiftoss/caip@workspace:packages/caip": version: 0.0.0-use.local resolution: "@shapeshiftoss/caip@workspace:packages/caip" dependencies: @@ -7726,15 +7716,6 @@ __metadata: languageName: unknown linkType: soft -"@shapeshiftoss/caip@npm:3.0.0": - version: 3.0.0 - resolution: "@shapeshiftoss/caip@npm:3.0.0" - peerDependencies: - "@shapeshiftoss/types": 3.1.3 - checksum: eaa5ea33330b137fe0819b7be0d1f0307c28e5abcf58f59fad583cbb6aab6e662412c7ec374c2fd9727ac84d815d0c4c60ffef93f0f2eefc9ded02281d69d8a4 - languageName: node - linkType: hard - "@shapeshiftoss/chain-adapters@workspace:^, @shapeshiftoss/chain-adapters@workspace:packages/chain-adapters": version: 0.0.0-use.local resolution: "@shapeshiftoss/chain-adapters@workspace:packages/chain-adapters" @@ -7808,15 +7789,15 @@ __metadata: languageName: node linkType: hard -"@shapeshiftoss/hdwallet-coinbase@npm:^1.50.4": - version: 1.50.4 - resolution: "@shapeshiftoss/hdwallet-coinbase@npm:1.50.4" +"@shapeshiftoss/hdwallet-coinbase@npm:1.51.0": + version: 1.51.0 + resolution: "@shapeshiftoss/hdwallet-coinbase@npm:1.51.0" dependencies: "@coinbase/wallet-sdk": ^3.6.6 - "@shapeshiftoss/hdwallet-core": 1.50.4 + "@shapeshiftoss/hdwallet-core": 1.51.0 eth-rpc-errors: ^4.0.3 lodash: ^4.17.21 - checksum: bcf0183e53794dbaabfff8d060bbd4d984de5150862e701d3e44042e8075e4786d303a3ca214cb8899c3f1e7629bec46b1887ada50dde3bc4161438af4d9dd8a + checksum: 7b08415270e1a6c8f3c1c06dd2743b0fa11bcc683efdbe6d144f552e02daebc790d2a6e98172da8a86c94caa8e4bb637ad3b7ac24d0c936aaf0c8dc4ade95502 languageName: node linkType: hard @@ -7846,23 +7827,9 @@ __metadata: languageName: node linkType: hard -"@shapeshiftoss/hdwallet-core@npm:^1.50.5-alpha.68": - version: 1.50.5-alpha.68 - resolution: "@shapeshiftoss/hdwallet-core@npm:1.50.5-alpha.68" - dependencies: - "@shapeshiftoss/proto-tx-builder": ^0.8.0 - eip-712: ^1.0.0 - eventemitter2: ^5.0.1 - lodash: ^4.17.21 - rxjs: ^6.4.0 - type-assertions: ^1.1.0 - checksum: 98d5eac360bf95376adf07802df4b8516ffa937a24a43a17a4cd9d8a9df6f68423ac880fac5007946dcf23b78a1cb5698cc17780b8e85e9e2c56a1495e1a37b5 - languageName: node - linkType: hard - -"@shapeshiftoss/hdwallet-core@npm:^1.50.8": - version: 1.50.8 - resolution: "@shapeshiftoss/hdwallet-core@npm:1.50.8" +"@shapeshiftoss/hdwallet-core@npm:1.51.0": + version: 1.51.0 + resolution: "@shapeshiftoss/hdwallet-core@npm:1.51.0" dependencies: "@shapeshiftoss/proto-tx-builder": ^0.8.0 eip-712: ^1.0.0 @@ -7870,29 +7837,29 @@ __metadata: lodash: ^4.17.21 rxjs: ^6.4.0 type-assertions: ^1.1.0 - checksum: d083e9255b6770d417127775a16469d6d6ba429812e04d524fbd465e4ebe9ac1290537c92bc0da869e90170251f8bcdbf40aad4b571a514353bbded505d4a19a + checksum: 9cffc3d4297cef8c26c35509b1fccba66d8966fe6b78c84b5563517bfebea1d9ffbc720a20014972cd17c062ab9980dd6e9ae47c3c4482fe8bdbfbf33a88ce52 languageName: node linkType: hard -"@shapeshiftoss/hdwallet-keepkey-webusb@npm:^1.50.4": - version: 1.50.4 - resolution: "@shapeshiftoss/hdwallet-keepkey-webusb@npm:1.50.4" +"@shapeshiftoss/hdwallet-keepkey-webusb@npm:1.51.0": + version: 1.51.0 + resolution: "@shapeshiftoss/hdwallet-keepkey-webusb@npm:1.51.0" dependencies: - "@shapeshiftoss/hdwallet-core": 1.50.4 - "@shapeshiftoss/hdwallet-keepkey": 1.50.4 - checksum: 963537056f9cffd88cc52d5eb02701f1a3d6a54b929e1fdba948958138e10a3f13d6e8f76b6663de112ec0473ab939a66130724ba24e4b237bf48968c49e53ae + "@shapeshiftoss/hdwallet-core": 1.51.0 + "@shapeshiftoss/hdwallet-keepkey": 1.51.0 + checksum: 597ac519d1d9466d17f8074aab04310ee8bb10dabe97f7631b879c15b347dc1b8a0c0b03c45ed3024fab40fc12b87cfdc92ee0786ab051000979c585ac0ebbac languageName: node linkType: hard -"@shapeshiftoss/hdwallet-keepkey@npm:1.50.4, @shapeshiftoss/hdwallet-keepkey@npm:^1.50.4": - version: 1.50.4 - resolution: "@shapeshiftoss/hdwallet-keepkey@npm:1.50.4" +"@shapeshiftoss/hdwallet-keepkey@npm:1.51.0": + version: 1.51.0 + resolution: "@shapeshiftoss/hdwallet-keepkey@npm:1.51.0" dependencies: "@ethereumjs/common": ^2.4.0 "@ethereumjs/tx": ^3.3.0 "@keepkey/device-protocol": ^7.12.2 "@shapeshiftoss/bitcoinjs-lib": 5.2.0-shapeshift.2 - "@shapeshiftoss/hdwallet-core": 1.50.4 + "@shapeshiftoss/hdwallet-core": 1.51.0 "@shapeshiftoss/proto-tx-builder": ^0.8.0 bignumber.js: ^9.0.1 bnb-javascript-sdk-nobroadcast: ^2.16.14 @@ -7905,42 +7872,42 @@ __metadata: p-lazy: ^3.1.0 semver: ^7.3.8 tiny-secp256k1: ^1.1.6 - checksum: d4349074a02e89fdc1b801f24db8f3e16ca52bae70a3d4b05bd697a5ec14a6368b841bd32467d692978c69000fc0661b655a8c6ce8c28a60c940d948b1569fd5 + checksum: ca3d0d19fdb48dc3c08d3a0e3f12e9c675d853f88a6ddc1c8404fe15e0c83a0f1ae5e672c985b29e271c30ee70f8812de3fe21ab29ce6f780b8f162c79c71282 languageName: node linkType: hard -"@shapeshiftoss/hdwallet-keplr@npm:^1.50.4": - version: 1.50.4 - resolution: "@shapeshiftoss/hdwallet-keplr@npm:1.50.4" +"@shapeshiftoss/hdwallet-keplr@npm:1.51.0": + version: 1.51.0 + resolution: "@shapeshiftoss/hdwallet-keplr@npm:1.51.0" dependencies: - "@shapeshiftoss/caip": 3.0.0 - "@shapeshiftoss/hdwallet-core": 1.50.4 + "@shapeshiftoss/caip": 8.15.0 + "@shapeshiftoss/hdwallet-core": 1.51.0 "@shapeshiftoss/proto-tx-builder": ^0.8.0 "@shapeshiftoss/types": 3.1.3 base64-js: ^1.5.1 lodash: ^4.17.21 - checksum: 37bdf5e9c37ccc61a83faba4718bd851c9165ed6f3e4bb8ef22c813753e9e3f064eebc7fb00caae01538573adcb8e6e5916f8ebf2b7641bb621d286e535aa4d0 + checksum: 62d104bc9aa3b0183eae400694e7d1d7c37e12f973e844b0e53b4441a67c89c81f9d33af2e4c0edd067a9d5e0fcf0c05278737b484eee6f5c18e57672cf0c5fb languageName: node linkType: hard -"@shapeshiftoss/hdwallet-metamask@npm:^1.50.4": - version: 1.50.4 - resolution: "@shapeshiftoss/hdwallet-metamask@npm:1.50.4" +"@shapeshiftoss/hdwallet-metamask@npm:1.51.0": + version: 1.51.0 + resolution: "@shapeshiftoss/hdwallet-metamask@npm:1.51.0" dependencies: "@metamask/detect-provider": ^1.2.0 "@metamask/onboarding": ^1.0.1 - "@shapeshiftoss/hdwallet-core": 1.50.4 + "@shapeshiftoss/hdwallet-core": 1.51.0 eth-rpc-errors: ^4.0.3 lodash: ^4.17.21 - checksum: 8f94654c2687749f697b2449161b0ae61844dbc7d2e6a1f003cbbe9e129b017429c76719c172a670d6a3188399d55d127cc494e080f75173f2dd757916ed6d36 + checksum: 44eed92dd9b06c102024de12cbc93966646f749b6094eaf8781e7497af6190f5d9be4bdaf523a88c98224bce2d920ee84f84e3f26d7c0556be1ea458cd482905 languageName: node linkType: hard -"@shapeshiftoss/hdwallet-native-vault@npm:^1.50.4": - version: 1.50.4 - resolution: "@shapeshiftoss/hdwallet-native-vault@npm:1.50.4" +"@shapeshiftoss/hdwallet-native-vault@npm:1.51.0": + version: 1.51.0 + resolution: "@shapeshiftoss/hdwallet-native-vault@npm:1.51.0" dependencies: - "@shapeshiftoss/hdwallet-native": 1.50.4 + "@shapeshiftoss/hdwallet-native": 1.51.0 bip39: ^3.0.4 hash-wasm: ^4.9.0 idb-keyval: ^6.0.3 @@ -7949,11 +7916,42 @@ __metadata: type-assertions: ^1.1.0 uuid: ^8.3.2 web-encoding: ^1.1.0 - checksum: e735dbf9f633a2a5633488b7d2ac59455081f4375f4733620d6ace040e8d6c4704571871905b0ccf2d9e6efb2f96a697b3d6c48faad2a48a6126ace5caffc556 + checksum: 0c7e1588042455ec879a1d4c7462517df0e623ca221c71bc2b9bb5846261bceff3221b4b0b3e9307b2f2d401f3adbdda022f5072a87c0cd1673d410e80d92fd6 languageName: node linkType: hard -"@shapeshiftoss/hdwallet-native@npm:1.50.4, @shapeshiftoss/hdwallet-native@npm:^1.50.4": +"@shapeshiftoss/hdwallet-native@npm:1.51.0": + version: 1.51.0 + resolution: "@shapeshiftoss/hdwallet-native@npm:1.51.0" + dependencies: + "@shapeshiftoss/bitcoinjs-lib": 5.2.0-shapeshift.2 + "@shapeshiftoss/fiosdk": 1.2.1-shapeshift.6 + "@shapeshiftoss/hdwallet-core": 1.51.0 + "@shapeshiftoss/proto-tx-builder": ^0.8.0 + "@zxing/text-encoding": ^0.9.0 + bchaddrjs: ^0.4.9 + bech32: ^1.1.4 + bignumber.js: ^9.0.1 + bip32: ^2.0.5 + bip39: ^3.0.2 + bnb-javascript-sdk-nobroadcast: ^2.16.14 + crypto-js: ^4.0.0 + eip-712: ^1.0.0 + ethers: 5.7.2 + eventemitter2: ^5.0.1 + funtypes: ^3.0.1 + lodash: ^4.17.21 + node-fetch: ^2.6.1 + p-lazy: ^3.1.0 + scrypt-js: ^3.0.1 + tendermint-tx-builder: ^1.0.9 + tiny-secp256k1: ^1.1.6 + web-encoding: ^1.1.0 + checksum: 07e3faea365353a6f8ec74f3f7cf67c7e4850b12a3cd0d1d25baaf7df87ade83251f55338bf5b33721e8c184c28758b08133d02372915091bcb106b090840452 + languageName: node + linkType: hard + +"@shapeshiftoss/hdwallet-native@npm:^1.50.4": version: 1.50.4 resolution: "@shapeshiftoss/hdwallet-native@npm:1.50.4" dependencies: @@ -7984,41 +7982,41 @@ __metadata: languageName: node linkType: hard -"@shapeshiftoss/hdwallet-shapeshift-multichain@npm:^1.50.5-alpha.70": - version: 1.50.5-alpha.72 - resolution: "@shapeshiftoss/hdwallet-shapeshift-multichain@npm:1.50.5-alpha.72" +"@shapeshiftoss/hdwallet-shapeshift-multichain@npm:1.51.0": + version: 1.51.0 + resolution: "@shapeshiftoss/hdwallet-shapeshift-multichain@npm:1.51.0" dependencies: "@metamask/detect-provider": ^1.2.0 "@metamask/onboarding": ^1.0.1 "@shapeshiftoss/common-api": ^9.3.0 - "@shapeshiftoss/hdwallet-core": ^1.50.5-alpha.68 - "@shapeshiftoss/metamask-snaps-adapter": ^1.0.0-alpha.28 - "@shapeshiftoss/metamask-snaps-types": ^1.0.0-alpha.22 + "@shapeshiftoss/hdwallet-core": 1.51.0 + "@shapeshiftoss/metamask-snaps-adapter": ^1.0.6 + "@shapeshiftoss/metamask-snaps-types": ^1.0.6 eth-rpc-errors: ^4.0.3 lodash: ^4.17.21 - checksum: 6e4b0319223d1da565203e94893f70ab93e90c4c960367bfa722f9c3a3f500a5120330cc5de122f77455035538ac0fc41f6d70ab861b10a988ed6d2b59f8e403 + checksum: c5eab57944162ce15e63509b061fe3f35276b0dd67226693ccb230c45d6f7a98ceb26408082b852702ed5cd5a99acc44f7963a631580e2ea553dd57d34fd02a1 languageName: node linkType: hard -"@shapeshiftoss/hdwallet-walletconnectv2@npm:1.50.8": - version: 1.50.8 - resolution: "@shapeshiftoss/hdwallet-walletconnectv2@npm:1.50.8" +"@shapeshiftoss/hdwallet-walletconnectv2@npm:1.51.0": + version: 1.51.0 + resolution: "@shapeshiftoss/hdwallet-walletconnectv2@npm:1.51.0" dependencies: - "@shapeshiftoss/hdwallet-core": ^1.50.8 + "@shapeshiftoss/hdwallet-core": 1.51.0 "@walletconnect/ethereum-provider": ^2.10.1 "@walletconnect/modal": ^2.6.2 ethers: ^5.6.5 - checksum: 28d626c04945b25bc31bc34f4e43bed3949ca1958d70d56421130857d0e1dd6dcd57b680eb995639666ae8db77aa89b4383141965cc112ff98c2274d972bdeea + checksum: a00e79c2d8f321586d88a15139f7fbe275ce3c788759a28a47949e94eefb429b4817a1a89ef1e745447761ff282e96f61ebe7d5bff9ce3746a5d69316b05f458 languageName: node linkType: hard -"@shapeshiftoss/hdwallet-xdefi@npm:^1.50.4": - version: 1.50.4 - resolution: "@shapeshiftoss/hdwallet-xdefi@npm:1.50.4" +"@shapeshiftoss/hdwallet-xdefi@npm:1.51.0": + version: 1.51.0 + resolution: "@shapeshiftoss/hdwallet-xdefi@npm:1.51.0" dependencies: - "@shapeshiftoss/hdwallet-core": 1.50.4 + "@shapeshiftoss/hdwallet-core": 1.51.0 lodash: ^4.17.21 - checksum: 4f956faff25c8dd531eee7b53abe59bc456b267f9dfa101cafc8f38ab160c5ccbbdcdb4abb417d8144520b337ec26d68efe911350687f597adadd352c642e7bb + checksum: 8818fdb9586ad854cb647df03f3e7088dc457b30ca800d3e145aab2bc00d6085b9b34812722a389bbb52457412de17d61cacc94fa93f2ffa20c7f2aa280bf9e3 languageName: node linkType: hard @@ -8029,17 +8027,17 @@ __metadata: languageName: node linkType: hard -"@shapeshiftoss/metamask-snaps-adapter@npm:^1.0.0-alpha.28": - version: 1.0.0-alpha.28 - resolution: "@shapeshiftoss/metamask-snaps-adapter@npm:1.0.0-alpha.28" +"@shapeshiftoss/metamask-snaps-adapter@npm:^1.0.6": + version: 1.0.8 + resolution: "@shapeshiftoss/metamask-snaps-adapter@npm:1.0.8" dependencies: "@ethersproject/providers": ^5.7.2 "@metamask/detect-provider": ^2.0.0 - "@metamask/snaps-ui": 1.0.1 + "@metamask/snaps-ui": 1.0.2 "@shapeshiftoss/hdwallet-core": ^1.50.4 "@shapeshiftoss/logger": ^1.1.3 - "@shapeshiftoss/metamask-snaps": ^1.0.0-alpha.27 - "@shapeshiftoss/metamask-snaps-types": ^1.0.0-alpha.22 + "@shapeshiftoss/metamask-snaps": ^1.0.8 + "@shapeshiftoss/metamask-snaps-types": ^1.0.8 p-queue: ^7.4.1 peerDependencies: "@shapeshiftoss/caip": "*" @@ -8047,25 +8045,25 @@ __metadata: eslint-plugin-react: "*" eslint-plugin-react-hooks: "*" webpack: "*" - checksum: 558fecdcbffa68a9bba8f996ddc7f8c4fdb5b234fac737a871b8ba1bf7307c681e36d7a7fa621a9bdc99fe3c0814b084415076cf7fd71724a8fddfa6eca7c94f + checksum: 1d956fea3c56442bcdb41946e8c62065a8a3dc57b82bdeebbcac6fadf3a98c1995d859ced19b20f154e0021508498276df402c49d81049ffc7105bb8f272fab1 languageName: node linkType: hard -"@shapeshiftoss/metamask-snaps-types@npm:^1.0.0-alpha.22": - version: 1.0.0-alpha.22 - resolution: "@shapeshiftoss/metamask-snaps-types@npm:1.0.0-alpha.22" +"@shapeshiftoss/metamask-snaps-types@npm:^1.0.6, @shapeshiftoss/metamask-snaps-types@npm:^1.0.8": + version: 1.0.8 + resolution: "@shapeshiftoss/metamask-snaps-types@npm:1.0.8" dependencies: "@metamask/types": ^1.1.0 "@shapeshiftoss/hdwallet-core": ^1.50.4 "@shapeshiftoss/hdwallet-native": ^1.50.4 "@shapeshiftoss/unchained-client": ^10.1.1 - checksum: d7b8dac40bea73f09293f1eb40560f8ae8e4803eb40dc2aab539d3a90221b109e67d31a708cd66a52ce1a6806593ee6e11ebf3dbbf8ecceb2434c97f64cba1f0 + checksum: 7f037790d795a8d508521afd72e74a53d3117e26a5df6b169e3f1619bd0ebd6e0af779ec5fb9a5152cb75ebebf7f0f3d22973283458c20d651a098ad3766271e languageName: node linkType: hard -"@shapeshiftoss/metamask-snaps@npm:^1.0.0-alpha.27": - version: 1.0.0-alpha.27 - resolution: "@shapeshiftoss/metamask-snaps@npm:1.0.0-alpha.27" +"@shapeshiftoss/metamask-snaps@npm:^1.0.8": + version: 1.0.8 + resolution: "@shapeshiftoss/metamask-snaps@npm:1.0.8" dependencies: "@ethersproject/providers": ^5.7.0 "@metamask/detect-provider": ^2.0.0 @@ -8076,7 +8074,7 @@ __metadata: "@shapeshiftoss/hdwallet-core": ^1.50.4 "@shapeshiftoss/hdwallet-native": ^1.50.4 "@shapeshiftoss/logger": ^1.1.2 - "@shapeshiftoss/metamask-snaps-types": ^1.0.0-alpha.22 + "@shapeshiftoss/metamask-snaps-types": ^1.0.8 "@shapeshiftoss/types": ^8.3.0 "@shapeshiftoss/unchained-client": 10.1.1 eth-rpc-errors: ^4.0.3 @@ -8093,7 +8091,7 @@ __metadata: eslint-plugin-react: "*" eslint-plugin-react-hooks: "*" webpack: "*" - checksum: b578e6ccf304fc67cbfe4c417e042f0617899695e2b61c32c5d7c358b84a4626da1033678ccfddf0aa936700e3f7fffd77f13848a5720728945d2affbd55b599 + checksum: 46ed4cf19ff9d30c0b8366732e41a94571928ba94d38f47eed5e72715a9ed082eabcb559001a3d4e07782961cb239a21bba8fc054cc2e2edb319899ef32ae6d4 languageName: node linkType: hard @@ -8188,17 +8186,17 @@ __metadata: "@shapeshiftoss/caip": "workspace:^" "@shapeshiftoss/chain-adapters": "workspace:^" "@shapeshiftoss/errors": "workspace:^" - "@shapeshiftoss/hdwallet-coinbase": ^1.50.4 - "@shapeshiftoss/hdwallet-core": ^1.50.4 - "@shapeshiftoss/hdwallet-keepkey": ^1.50.4 - "@shapeshiftoss/hdwallet-keepkey-webusb": ^1.50.4 - "@shapeshiftoss/hdwallet-keplr": ^1.50.4 - "@shapeshiftoss/hdwallet-metamask": ^1.50.4 - "@shapeshiftoss/hdwallet-native": ^1.50.4 - "@shapeshiftoss/hdwallet-native-vault": ^1.50.4 - "@shapeshiftoss/hdwallet-shapeshift-multichain": ^1.50.5-alpha.70 - "@shapeshiftoss/hdwallet-walletconnectv2": 1.50.8 - "@shapeshiftoss/hdwallet-xdefi": ^1.50.4 + "@shapeshiftoss/hdwallet-coinbase": 1.51.0 + "@shapeshiftoss/hdwallet-core": 1.51.0 + "@shapeshiftoss/hdwallet-keepkey": 1.51.0 + "@shapeshiftoss/hdwallet-keepkey-webusb": 1.51.0 + "@shapeshiftoss/hdwallet-keplr": 1.51.0 + "@shapeshiftoss/hdwallet-metamask": 1.51.0 + "@shapeshiftoss/hdwallet-native": 1.51.0 + "@shapeshiftoss/hdwallet-native-vault": 1.51.0 + "@shapeshiftoss/hdwallet-shapeshift-multichain": 1.51.0 + "@shapeshiftoss/hdwallet-walletconnectv2": 1.51.0 + "@shapeshiftoss/hdwallet-xdefi": 1.51.0 "@shapeshiftoss/types": "workspace:^" "@shapeshiftoss/unchained-client": "workspace:^" "@snapshot-labs/snapshot.js": ^0.6.1 From aaf5b2f01367e1ded988339124b650635e871321 Mon Sep 17 00:00:00 2001 From: woody <125113430+woodenfurniture@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:20:19 +1100 Subject: [PATCH 04/10] feat: use loading state on all modal submit buttons (#5379) --- .../components/Account.tsx | 6 +- .../components/AccountSelectionByChainId.tsx | 16 +++-- .../components/ChainReferenceCard.tsx | 28 +++++---- .../modals/ContractInteractionBreakdown.tsx | 63 ++++++++++--------- .../modals/CosmosSignMessageConfirmation.tsx | 31 +++++++-- .../modals/EIP155SignMessageConfirmation.tsx | 37 +++++++++-- .../EIP155SignTypedDataConfirmation.tsx | 37 +++++++++-- .../modals/EIP155TransactionConfirmation.tsx | 31 ++++++--- .../components/modals/SessionProposal.tsx | 15 ++++- .../modals/connect/ConnectContent.tsx | 15 ++--- .../hooks/useCallRequestEvmFees.ts | 8 ++- .../walletConnectToDapps/hooks/useGetAbi.tsx | 29 +++------ .../hooks/useIsInteractingWithContract.ts | 4 +- .../hooks/useWalletConnectState.ts | 9 +-- .../walletConnectToDapps/typeGuards.ts | 18 ++---- 15 files changed, 232 insertions(+), 115 deletions(-) diff --git a/src/plugins/walletConnectToDapps/components/Account.tsx b/src/plugins/walletConnectToDapps/components/Account.tsx index 38d79313e67..f7a8c67a359 100644 --- a/src/plugins/walletConnectToDapps/components/Account.tsx +++ b/src/plugins/walletConnectToDapps/components/Account.tsx @@ -1,6 +1,6 @@ import { Checkbox, Flex } from '@chakra-ui/react' import type { AccountId } from '@shapeshiftoss/caip' -import type { FC } from 'react' +import { type FC, useCallback } from 'react' import { MiddleEllipsis } from 'components/MiddleEllipsis/MiddleEllipsis' import { RawText } from 'components/Text' import { accountIdToLabel } from 'state/slices/portfolioSlice/utils' @@ -13,8 +13,10 @@ interface IProps { } export const Account: FC = ({ accountId, isSelected, toggleAccountId, accountNumber }) => { + const handleChange = useCallback(() => toggleAccountId(accountId), [accountId, toggleAccountId]) + return ( - toggleAccountId(accountId)} width='full'> + Account #{accountNumber} diff --git a/src/plugins/walletConnectToDapps/components/AccountSelectionByChainId.tsx b/src/plugins/walletConnectToDapps/components/AccountSelectionByChainId.tsx index a8f76091a9d..4bf2e2c3cc7 100644 --- a/src/plugins/walletConnectToDapps/components/AccountSelectionByChainId.tsx +++ b/src/plugins/walletConnectToDapps/components/AccountSelectionByChainId.tsx @@ -22,16 +22,22 @@ export const AccountSelectionByChainId: FC = ({ }) => { const translate = useTranslate() const [allChecked, setAllChecked] = useState(false) - const translateKey = (key: string) => `plugins.walletConnectToDapps.modal.sessionProposal.${key}` + const translateKey = useCallback( + (key: string) => `plugins.walletConnectToDapps.modal.sessionProposal.${key}`, + [], + ) const filter = useMemo(() => ({ chainId }), [chainId]) const accountIdsByAccountNumberChainId = useAppSelector(s => selectPortfolioAccountsGroupedByNumberByChainId(s, filter), ) - const accountIds = Object.entries(accountIdsByAccountNumberChainId).flatMap( - ([_, accountIds]) => accountIds, + const accountIds = useMemo( + () => Object.entries(accountIdsByAccountNumberChainId).flatMap(([_, accountIds]) => accountIds), + [accountIdsByAccountNumberChainId], ) - const selectedAccountIdsByChainId = accountIds.filter(accountId => - selectedAccountIds.includes(accountId), + + const selectedAccountIdsByChainId = useMemo( + () => accountIds.filter(accountId => selectedAccountIds.includes(accountId)), + [accountIds, selectedAccountIds], ) const renderAccounts = useMemo(() => { diff --git a/src/plugins/walletConnectToDapps/components/ChainReferenceCard.tsx b/src/plugins/walletConnectToDapps/components/ChainReferenceCard.tsx index 52d6b0183e2..7ab0610adaa 100644 --- a/src/plugins/walletConnectToDapps/components/ChainReferenceCard.tsx +++ b/src/plugins/walletConnectToDapps/components/ChainReferenceCard.tsx @@ -14,7 +14,7 @@ import { import { Tag } from '@chakra-ui/tag' import { AccountSelectionByChainId } from 'plugins/walletConnectToDapps/components/AccountSelectionByChainId' import type { FC } from 'react' -import { useMemo } from 'react' +import { useCallback, useMemo } from 'react' import { useTranslate } from 'react-polyglot' import { AssetIcon } from 'components/AssetIcon' import { Row } from 'components/Row/Row' @@ -30,6 +30,10 @@ type ChainReferenceCardProps = { toggleAccountId: (accountId: string) => void } +const borderRadiusProp = { base: 'lg', md: 'xl' } +const pxProp = { base: 4, md: 4 } +const pProp = { base: 0, md: 0 } + export const ChainReferenceCard: FC = ({ methods, events, @@ -42,7 +46,10 @@ export const ChainReferenceCard: FC = ({ const translate = useTranslate() const asset = useAppSelector(s => selectFeeAssetByChainId(s, chainId)) const borderColor = useColorModeValue('blackAlpha.100', 'whiteAlpha.200') - const translateKey = (key: string) => `plugins.walletConnectToDapps.modal.sessionProposal.${key}` + const translateKey = useCallback( + (key: string) => `plugins.walletConnectToDapps.modal.sessionProposal.${key}`, + [], + ) const renderEvents = useMemo(() => { return events.map(event => ( @@ -59,21 +66,20 @@ export const ChainReferenceCard: FC = ({ )) }, [methods]) + + const hoverBg = useColorModeValue('blackAlpha.50', 'whiteAlpha.50') + const hoverProp = useMemo(() => ({ bg: hoverBg }), [hoverBg]) + return ( - + @@ -85,7 +91,7 @@ export const ChainReferenceCard: FC = ({ - + }> {translate(translateKey('methods'))} diff --git a/src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx b/src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx index a2f4c7ae03a..1a0a31a6677 100644 --- a/src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx +++ b/src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx @@ -7,7 +7,7 @@ import { ModalCollapsableSection } from 'plugins/walletConnectToDapps/components import { useGetAbi } from 'plugins/walletConnectToDapps/hooks/useGetAbi' import type { EthSendTransactionCallRequest } from 'plugins/walletConnectToDapps/types' import type { FC } from 'react' -import { Fragment, useMemo } from 'react' +import { Fragment, useCallback, useMemo } from 'react' import { FaCode } from 'react-icons/fa' import { Amount } from 'components/Amount/Amount' import { MiddleEllipsis } from 'components/MiddleEllipsis/MiddleEllipsis' @@ -45,35 +45,38 @@ export const ContractInteractionBreakdown: FC const addressColor = useColorModeValue('blue.500', 'blue.200') - const renderAbiInput = (input: ParamType, index: number): JSX.Element => { - const inputValue = transaction?.args[index].toString() - switch (input.type) { - case 'bytes[]': - return - case 'address': - return ( - - - - - - {feeAsset && ( - - )} - - ) - case 'tuple': - default: - return ( - - {inputValue} - - ) - } - } + const renderAbiInput = useCallback( + (input: ParamType, index: number): JSX.Element => { + const inputValue = transaction?.args[index].toString() + switch (input.type) { + case 'bytes[]': + return + case 'address': + return ( + + + + + + {feeAsset && ( + + )} + + ) + case 'tuple': + default: + return ( + + {inputValue} + + ) + } + }, + [addressColor, feeAsset, transaction?.args], + ) return ( -> = ({ onConfirm: handleConfirm, onReject: handleReject, state, topic }) => { +> = ({ onConfirm, onReject, state, topic }) => { + const [isLoading, setIsLoading] = useState(false) const { address, chainId } = useWalletConnectState(state) const peerMetadata = state.sessionsByTopic[topic]?.peer.metadata @@ -42,6 +45,18 @@ export const CosmosSignMessageConfirmationModal: FC< const cardBg = useColorModeValue('white', 'gray.850') const request = state.modalData.requestEvent?.params.request + const handleConfirm = useCallback(async () => { + setIsLoading(true) + await onConfirm() + setIsLoading(false) + }, [onConfirm]) + + const handleReject = useCallback(async () => { + setIsLoading(true) + await onReject() + setIsLoading(false) + }, [onReject]) + const methodSpecificContent: JSX.Element | null = useMemo(() => { if (request?.method === CosmosSigningMethod.COSMOS_SIGN_AMINO) { const { @@ -161,11 +176,19 @@ export const CosmosSignMessageConfirmationModal: FC< colorScheme='blue' type='submit' onClick={handleConfirm} - isDisabled={true} + isDisabled={true} // coming soon + _disabled={disabledProp} + isLoading={isLoading} > {translate('plugins.walletConnectToDapps.modal.signMessage.comingSoon')} - diff --git a/src/plugins/walletConnectToDapps/components/modals/EIP155SignMessageConfirmation.tsx b/src/plugins/walletConnectToDapps/components/modals/EIP155SignMessageConfirmation.tsx index 3aadb8db279..dc4329a79a6 100644 --- a/src/plugins/walletConnectToDapps/components/modals/EIP155SignMessageConfirmation.tsx +++ b/src/plugins/walletConnectToDapps/components/modals/EIP155SignMessageConfirmation.tsx @@ -17,7 +17,7 @@ import type { EthSignCallRequest, } from 'plugins/walletConnectToDapps/types' import type { WalletConnectRequestModalProps } from 'plugins/walletConnectToDapps/WalletConnectModalManager' -import type { FC } from 'react' +import { type FC, useCallback, useState } from 'react' import { useTranslate } from 'react-polyglot' import { FoxIcon } from 'components/Icons/FoxIcon' import { RawText, Text } from 'components/Text' @@ -25,9 +25,12 @@ import { useWallet } from 'hooks/useWallet/useWallet' import { selectFeeAssetByChainId } from 'state/slices/selectors' import { useAppSelector } from 'state/store' +const disabledProp = { opacity: 0.5, cursor: 'not-allowed', userSelect: 'none' } + export const EIP155SignMessageConfirmationModal: FC< WalletConnectRequestModalProps -> = ({ onConfirm: handleConfirm, onReject: handleReject, state, topic }) => { +> = ({ onConfirm, onReject, state, topic }) => { + const [isLoading, setIsLoading] = useState(false) const { address, message, chainId } = useWalletConnectState(state) const peerMetadata = state.sessionsByTopic[topic]?.peer.metadata @@ -40,6 +43,18 @@ export const EIP155SignMessageConfirmationModal: FC< const WalletIcon = walletInfo?.icon ?? FoxIcon const cardBg = useColorModeValue('white', 'gray.850') + const handleConfirm = useCallback(async () => { + setIsLoading(true) + await onConfirm() + setIsLoading(false) + }, [onConfirm]) + + const handleReject = useCallback(async () => { + setIsLoading(true) + await onReject() + setIsLoading(false) + }, [onReject]) + if (!peerMetadata) return null return ( @@ -79,10 +94,24 @@ export const EIP155SignMessageConfirmationModal: FC< translation='plugins.walletConnectToDapps.modal.signMessage.description' /> - - diff --git a/src/plugins/walletConnectToDapps/components/modals/EIP155SignTypedDataConfirmation.tsx b/src/plugins/walletConnectToDapps/components/modals/EIP155SignTypedDataConfirmation.tsx index f32ae82d81a..bacb62f57f5 100644 --- a/src/plugins/walletConnectToDapps/components/modals/EIP155SignTypedDataConfirmation.tsx +++ b/src/plugins/walletConnectToDapps/components/modals/EIP155SignTypedDataConfirmation.tsx @@ -5,7 +5,7 @@ import { TypedMessageInfo } from 'plugins/walletConnectToDapps/components/modals import { useWalletConnectState } from 'plugins/walletConnectToDapps/hooks/useWalletConnectState' import type { EthSignTypedDataCallRequest } from 'plugins/walletConnectToDapps/types' import type { WalletConnectRequestModalProps } from 'plugins/walletConnectToDapps/WalletConnectModalManager' -import type { FC } from 'react' +import { type FC, useCallback, useState } from 'react' import { useTranslate } from 'react-polyglot' import { FoxIcon } from 'components/Icons/FoxIcon' import { Text } from 'components/Text' @@ -14,9 +14,12 @@ import { assertIsDefined } from 'lib/utils' import { selectFeeAssetByChainId } from 'state/slices/selectors' import { useAppSelector } from 'state/store' +const disabledProp = { opacity: 0.5, cursor: 'not-allowed', userSelect: 'none' } + export const EIP155SignTypedDataConfirmation: FC< WalletConnectRequestModalProps -> = ({ onConfirm: handleConfirm, onReject: handleReject, state }) => { +> = ({ onConfirm, onReject, state }) => { + const [isLoading, setIsLoading] = useState(false) const { address, message, chainId } = useWalletConnectState(state) assertIsDefined(message) @@ -28,6 +31,18 @@ export const EIP155SignTypedDataConfirmation: FC< const walletInfo = useWallet().state.walletInfo const WalletIcon = walletInfo?.icon ?? FoxIcon + const handleConfirm = useCallback(async () => { + setIsLoading(true) + await onConfirm() + setIsLoading(false) + }, [onConfirm]) + + const handleReject = useCallback(async () => { + setIsLoading(true) + await onReject() + setIsLoading(false) + }, [onReject]) + return ( <> @@ -44,10 +59,24 @@ export const EIP155SignTypedDataConfirmation: FC< translation='plugins.walletConnectToDapps.modal.signMessage.description' /> - - diff --git a/src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx b/src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx index 8a8c1d49405..bef64c08b63 100644 --- a/src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx +++ b/src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx @@ -19,7 +19,6 @@ import { ModalSection } from 'plugins/walletConnectToDapps/components/modals/Mod import { TransactionAdvancedParameters } from 'plugins/walletConnectToDapps/components/modals/TransactionAdvancedParameters' import { useCallRequestEvmFees } from 'plugins/walletConnectToDapps/hooks/useCallRequestEvmFees' import { useWalletConnectState } from 'plugins/walletConnectToDapps/hooks/useWalletConnectState' -import { assertIsTransactionParams } from 'plugins/walletConnectToDapps/typeGuards' import type { CustomTransactionData, EthSendTransactionCallRequest, @@ -35,10 +34,13 @@ import { useTranslate } from 'react-polyglot' import { CircularProgress } from 'components/CircularProgress/CircularProgress' import { FoxIcon } from 'components/Icons/FoxIcon' import { Text } from 'components/Text' +import { useErrorHandler } from 'hooks/useErrorToast/useErrorToast' import { useWallet } from 'hooks/useWallet/useWallet' import { selectFeeAssetByChainId } from 'state/slices/selectors' import { useAppSelector } from 'state/store' +const disabledProp = { opacity: 0.5, cursor: 'not-allowed', userSelect: 'none' } + export const EIP155TransactionConfirmation: FC< WalletConnectRequestModalProps > = ({ onConfirm: handleConfirm, onReject: handleReject, state }) => { @@ -49,10 +51,9 @@ export const EIP155TransactionConfirmation: FC< selectFeeAssetByChainId(state, chainId ?? ''), ) - transaction && assertIsTransactionParams(transaction) - - const { feeAsset, fees, feeAssetPrice } = useCallRequestEvmFees(state) + const { isLoading, feeAsset, fees, feeAssetPrice } = useCallRequestEvmFees(state) + const { showErrorToast } = useErrorHandler() const translate = useTranslate() const cardBg = useColorModeValue('white', 'gray.850') const { @@ -75,14 +76,23 @@ export const EIP155TransactionConfirmation: FC< }, }) - if (isInteractingWithContract === null) + if (isLoading || isInteractingWithContract === null) return (
) - if (!transaction) return null + // if the transaction is missing the dapp sent invalid params + if (!transaction) { + showErrorToast({ + message: 'unable to handle tx due to invalid params', + params: state.modalData.requestEvent?.params, + }) + handleReject() + return null + } + return ( @@ -159,10 +169,17 @@ export const EIP155TransactionConfirmation: FC< onClick={form.handleSubmit(handleConfirm)} isLoading={form.formState.isSubmitting} isDisabled={!fees} + _disabled={disabledProp} > {translate('plugins.walletConnectToDapps.modal.signMessage.confirm')} - diff --git a/src/plugins/walletConnectToDapps/components/modals/SessionProposal.tsx b/src/plugins/walletConnectToDapps/components/modals/SessionProposal.tsx index 444094d26c5..3313c7b3587 100644 --- a/src/plugins/walletConnectToDapps/components/modals/SessionProposal.tsx +++ b/src/plugins/walletConnectToDapps/components/modals/SessionProposal.tsx @@ -84,6 +84,7 @@ const SessionProposal: FC = ({ const { id, params } = proposal const { proposer, requiredNamespaces, optionalNamespaces } = params + const [isLoading, setIsLoading] = useState(false) const [selectedAccountIds, setSelectedAccountIds] = useState([]) const toggleAccountId = useCallback((accountId: string) => { setSelectedAccountIds(previousState => @@ -146,6 +147,8 @@ const SessionProposal: FC = ({ return } + setIsLoading(true) + const session = await web3wallet.approveSession({ id: proposal.id, namespaces: approvalNamespaces, @@ -155,10 +158,13 @@ const SessionProposal: FC = ({ }, [approvalNamespaces, dispatch, handleClose, proposal, web3wallet]) const handleReject = useCallback(async () => { + setIsLoading(true) + await web3wallet.rejectSession({ id, reason: getSdkError('USER_REJECTED_METHODS'), }) + handleClose() }, [handleClose, id, web3wallet]) @@ -229,10 +235,17 @@ const SessionProposal: FC = ({ !allNamespacesHaveAccounts } _disabled={disabledProp} + isLoading={isLoading} > {translate('plugins.walletConnectToDapps.modal.signMessage.confirm')} - diff --git a/src/plugins/walletConnectToDapps/components/modals/connect/ConnectContent.tsx b/src/plugins/walletConnectToDapps/components/modals/connect/ConnectContent.tsx index 33eb6741bec..1145621ce3e 100644 --- a/src/plugins/walletConnectToDapps/components/modals/connect/ConnectContent.tsx +++ b/src/plugins/walletConnectToDapps/components/modals/connect/ConnectContent.tsx @@ -12,7 +12,7 @@ import { VStack, } from '@chakra-ui/react' import { isWalletConnectV2Uri } from 'plugins/walletConnectToDapps/components/modals/connect/utils' -import { useCallback, useState } from 'react' +import { useCallback, useMemo, useState } from 'react' import { useForm, useWatch } from 'react-hook-form' import { useTranslate } from 'react-polyglot' import { QRCodeIcon } from 'components/Icons/QRCode' @@ -36,7 +36,7 @@ export const ConnectContent: React.FC = ({ const [isQrCodeView, setIsQrCodeView] = useState(false) const toggleQrCodeView = useCallback(() => setIsQrCodeView(v => !v), []) - const handleForm = (values: FormValues) => handleConnect(values.uri) + const handleForm = useCallback((values: FormValues) => handleConnect(values.uri), [handleConnect]) const { register, handleSubmit, control, formState, setValue } = useForm({ mode: 'onChange', @@ -54,10 +54,7 @@ export const ConnectContent: React.FC = ({ const uri = useWatch({ control, name: 'uri' }) const isValidUri = isWalletConnectV2Uri(uri) - if (isQrCodeView) - return - - const connectTranslation = (() => { + const connectTranslation = useMemo(() => { const commonString = 'plugins.walletConnectToDapps.modal.connect' switch (true) { case uri === '': @@ -67,7 +64,11 @@ export const ConnectContent: React.FC = ({ default: return `${commonString}.connect` } - })() + }, [isValidUri, uri]) + + if (isQrCodeView) { + return + } return ( diff --git a/src/plugins/walletConnectToDapps/hooks/useCallRequestEvmFees.ts b/src/plugins/walletConnectToDapps/hooks/useCallRequestEvmFees.ts index 05d131e0184..9dad0c0ae91 100644 --- a/src/plugins/walletConnectToDapps/hooks/useCallRequestEvmFees.ts +++ b/src/plugins/walletConnectToDapps/hooks/useCallRequestEvmFees.ts @@ -2,7 +2,6 @@ import { fromAccountId } from '@shapeshiftoss/caip' import type { EvmBaseAdapter, EvmChainId } from '@shapeshiftoss/chain-adapters' import { FeeDataKey } from '@shapeshiftoss/chain-adapters' import { useWalletConnectState } from 'plugins/walletConnectToDapps/hooks/useWalletConnectState' -import { assertIsTransactionParams } from 'plugins/walletConnectToDapps/typeGuards' import type { WalletConnectState } from 'plugins/walletConnectToDapps/types' import { getFeesForTx } from 'plugins/walletConnectToDapps/utils' import { useEffect, useMemo, useState } from 'react' @@ -14,6 +13,7 @@ import { useAppSelector } from 'state/store' export function useCallRequestEvmFees(state: WalletConnectState) { const [fees, setFees] = useState() + const [isLoading, setIsLoading] = useState(false) const { chainAdapter, chainId, accountId, transaction } = useWalletConnectState(state) const assets = useAppSelector(selectAssets) @@ -35,7 +35,8 @@ export function useCallRequestEvmFees(state: WalletConnectState) { const adapter = getChainAdapterManager().get(chainId) if (!(address && chainId && feeAsset && feeAssetPrice && adapter)) return ;(async () => { - assertIsTransactionParams(transaction) + setIsLoading(true) + const estimatedFees = await getFeesForTx( transaction, adapter as unknown as EvmBaseAdapter, @@ -75,8 +76,9 @@ export function useCallRequestEvmFees(state: WalletConnectState) { initialFees, ) setFees(result) + setIsLoading(false) })() }, [accountId, chainId, feeAsset, feeAssetPrice, transaction]) - return { fees, feeAsset, feeAssetPrice } + return { isLoading, fees, feeAsset, feeAssetPrice } } diff --git a/src/plugins/walletConnectToDapps/hooks/useGetAbi.tsx b/src/plugins/walletConnectToDapps/hooks/useGetAbi.tsx index 8fe826e0fc0..085f62d965d 100644 --- a/src/plugins/walletConnectToDapps/hooks/useGetAbi.tsx +++ b/src/plugins/walletConnectToDapps/hooks/useGetAbi.tsx @@ -48,27 +48,25 @@ export const useGetAbi = ( const sighash = data.substring(0, 10).toLowerCase() - // check for proxy methods on the root interface - let proxyFunctionNameIfExists: string | undefined - if (rootContractInterface) { - const rootFunctions = Object.values(rootContractInterface.functions) - proxyFunctionNameIfExists = Object.values(PROXY_CONTRACT_METHOD_NAME).find(x => - rootFunctions.find(y => y.name === x), - ) - } - useEffect(() => { + // check for proxy methods on the root interface + let proxyFunctionNameIfExists: string | undefined + if (rootContractInterface) { + const rootFunctions = Object.values(rootContractInterface.functions) + proxyFunctionNameIfExists = Object.values(PROXY_CONTRACT_METHOD_NAME).find(x => + rootFunctions.find(y => y.name === x), + ) + } + ;(async () => { let implementationAddress: string | null try { switch (proxyFunctionNameIfExists) { case PROXY_CONTRACT_METHOD_NAME.ZeroEx: - console.debug('proxyFunctionName is "getFunctionImplementation"') implementationAddress = await rootContractWithProvider?.getFunctionImplementation(sighash) break case PROXY_CONTRACT_METHOD_NAME.EIP1967: - console.debug('proxyFunctionName is "implementation"') const paddedImplementationAddress = await provider.getStorageAt( contractAddress, EIP1967_IMPLEMENTATION_SLOT, @@ -89,14 +87,7 @@ export const useGetAbi = ( setProxyContractImplementation(null) } })() - }, [ - rootContractInterface, - rootContractWithProvider, - sighash, - provider, - proxyFunctionNameIfExists, - contractAddress, - ]) + }, [rootContractInterface, rootContractWithProvider, sighash, provider, contractAddress]) const { data: contractImplementationRawAbiData } = useGetContractAbiQuery( proxyContractImplementation ?? skipToken, diff --git a/src/plugins/walletConnectToDapps/hooks/useIsInteractingWithContract.ts b/src/plugins/walletConnectToDapps/hooks/useIsInteractingWithContract.ts index c0098a72af3..33d4cf4a7c1 100644 --- a/src/plugins/walletConnectToDapps/hooks/useIsInteractingWithContract.ts +++ b/src/plugins/walletConnectToDapps/hooks/useIsInteractingWithContract.ts @@ -8,7 +8,7 @@ export const useIsInteractingWithContract = ({ }: { evmChainId: ChainId | undefined address: string | undefined -}): { isInteractingWithContract: boolean | null } => { +}): boolean | null => { const [isInteractingWithContract, setIsInteractingWithContract] = useState(null) useEffect(() => { ;(async () => { @@ -19,5 +19,5 @@ export const useIsInteractingWithContract = ({ })() }, [address, evmChainId]) - return { isInteractingWithContract } + return isInteractingWithContract } diff --git a/src/plugins/walletConnectToDapps/hooks/useWalletConnectState.ts b/src/plugins/walletConnectToDapps/hooks/useWalletConnectState.ts index ccb2499d310..8d191f522b7 100644 --- a/src/plugins/walletConnectToDapps/hooks/useWalletConnectState.ts +++ b/src/plugins/walletConnectToDapps/hooks/useWalletConnectState.ts @@ -14,6 +14,7 @@ import { getWalletAccountFromEthParams, getWalletAddressFromEthSignParams, } from 'plugins/walletConnectToDapps/utils' +import { useMemo } from 'react' import { getChainAdapterManager } from 'context/PluginProvider/chainAdapterSingleton' import { selectPortfolioAccountMetadata } from 'state/slices/portfolioSlice/selectors' import { useAppSelector } from 'state/store' @@ -34,17 +35,17 @@ export const useWalletConnectState = (state: WalletConnectState) => { const connectedAccounts = extractAllConnectedAccounts(sessionsByTopic) - const address = (() => { + const address = useMemo(() => { if (requestParams && isEthSignParams(requestParams)) return getWalletAddressFromEthSignParams(connectedAccounts, requestParams) if (requestParams && isTransactionParamsArray(requestParams)) return requestParams[0].from if (requestParams) return requestParams.signerAddress else return undefined - })() + }, [connectedAccounts, requestParams]) const accountMetadataById = useAppSelector(selectPortfolioAccountMetadata) - const accountId = (() => { + const accountId = useMemo(() => { if ( requestParams && (isEthSignParams(requestParams) || isTransactionParamsArray(requestParams)) @@ -52,7 +53,7 @@ export const useWalletConnectState = (state: WalletConnectState) => { return getWalletAccountFromEthParams(connectedAccounts, requestParams) if (requestParams) return getWalletAccountFromCosmosParams(connectedAccounts, requestParams) else return undefined - })() + }, [connectedAccounts, requestParams]) const accountMetadata = accountId ? accountMetadataById[accountId] : undefined diff --git a/src/plugins/walletConnectToDapps/typeGuards.ts b/src/plugins/walletConnectToDapps/typeGuards.ts index 0a3b82cfc5f..6b7ec449029 100644 --- a/src/plugins/walletConnectToDapps/typeGuards.ts +++ b/src/plugins/walletConnectToDapps/typeGuards.ts @@ -8,7 +8,7 @@ import type { WalletConnectRequest, } from 'plugins/walletConnectToDapps/types' import { EIP155_SigningMethod } from 'plugins/walletConnectToDapps/types' -import { getTypeGuardAssertion, isTruthy } from 'lib/utils' +import { isTruthy } from 'lib/utils' export const isTransactionParamsArray = ( transactions: RequestParams | undefined, @@ -48,14 +48,8 @@ export const isTransactionParams = ( transaction: TransactionParams | string | undefined, ): transaction is TransactionParams => typeof transaction === 'object' && - !!transaction?.from && - !!transaction?.to && - !!transaction?.data && - ((!!transaction?.gasLimit && !!transaction?.gasPrice) || !!transaction?.gas) - -export const assertIsTransactionParams: ( - transaction: TransactionParams | string | undefined, -) => asserts transaction is TransactionParams = getTypeGuardAssertion( - isTransactionParams, - 'Transaction has no transaction params', -) + transaction !== null && + !!transaction.from && + !!transaction.to && + !!transaction.data && + ((!!transaction.gasLimit && !!transaction.gasPrice) || !!transaction.gas) From f263bb98069f412d76a94ea78861904cf7e6be07 Mon Sep 17 00:00:00 2001 From: woody <125113430+woodenfurniture@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:21:20 +1100 Subject: [PATCH 05/10] fix: walletconnect should reject requests on modal close (#5385) --- .../WalletConnectModalManager.tsx | 47 ++- .../components/modals/SessionProposal.tsx | 319 +++++++++--------- src/plugins/walletConnectToDapps/types.ts | 4 + 3 files changed, 208 insertions(+), 162 deletions(-) diff --git a/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx b/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx index 8195fbe9f58..89a00fcc311 100644 --- a/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx +++ b/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx @@ -31,6 +31,7 @@ import type { EthSignCallRequest, EthSignTransactionCallRequest, EthSignTypedDataCallRequest, + SessionProposalRef, WalletConnectAction, WalletConnectContextType, WalletConnectState, @@ -38,7 +39,7 @@ import type { import { WalletConnectActionType, WalletConnectModal } from 'plugins/walletConnectToDapps/types' import { approveCosmosRequest } from 'plugins/walletConnectToDapps/utils/CosmosRequestHandlerUtil' import { approveEIP155Request } from 'plugins/walletConnectToDapps/utils/EIP155RequestHandlerUtil' -import { type Dispatch, type FC, useCallback, useMemo } from 'react' +import { type Dispatch, type FC, useCallback, useMemo, useRef } from 'react' import { WalletConnectIcon } from 'components/Icons/WalletConnectIcon' import { Text } from 'components/Text' import { useWallet } from 'hooks/useWallet/useWallet' @@ -77,6 +78,7 @@ export const WalletConnectModalManager: FC = ({ dispatch, }) => { const wallet = useWallet().state.wallet + const sessionProposalRef = useRef(null) const { chainAdapter, requestEvent, accountMetadata, accountId } = useWalletConnectState(state) const { activeModal, web3wallet } = state @@ -160,20 +162,47 @@ export const WalletConnectModalManager: FC = ({ topic, response, }) + }, [requestEvent, topic, web3wallet]) + + const handleRejectRequestAndClose = useCallback(async () => { + switch (activeModal) { + case WalletConnectModal.SessionProposal: + await sessionProposalRef.current?.handleReject() + break + case WalletConnectModal.SignEIP155MessageConfirmation: + case WalletConnectModal.SignEIP155TypedDataConfirmation: + case WalletConnectModal.SignEIP155TransactionConfirmation: + case WalletConnectModal.SendEIP155TransactionConfirmation: + case WalletConnectModal.SendCosmosTransactionConfirmation: + await handleRejectRequest() + break + case undefined: + break + default: + assertUnreachable(activeModal) + } + handleClose() - }, [handleClose, requestEvent, topic, web3wallet]) + }, [activeModal, handleClose, handleRejectRequest]) const modalContent = useMemo(() => { if (!web3wallet || !activeModal || !isSessionProposalState(state)) return null switch (activeModal) { case WalletConnectModal.SessionProposal: - return + return ( + + ) case WalletConnectModal.SignEIP155MessageConfirmation: if (!topic) return null return ( >} topic={topic} @@ -184,7 +213,7 @@ export const WalletConnectModalManager: FC = ({ return ( >} topic={topic} @@ -196,7 +225,7 @@ export const WalletConnectModalManager: FC = ({ return ( = ({ return ( = ({ handleClose, handleConfirmCosmosRequest, handleConfirmEIP155Request, - handleRejectRequest, + handleRejectRequestAndClose, state, topic, web3wallet, @@ -241,7 +270,7 @@ export const WalletConnectModalManager: FC = ({ return ( = ({ - onClose: handleClose, - state: { - modalData: { proposal }, - web3wallet, - }, - dispatch, -}) => { - assertIsDefined(proposal) +const SessionProposal = forwardRef( + ( + { + onClose: handleClose, + state: { + modalData: { proposal }, + web3wallet, + }, + dispatch, + }: WalletConnectSessionModalProps, + ref, + ) => { + assertIsDefined(proposal) - const wallet = useWallet().state.wallet - const translate = useTranslate() + const wallet = useWallet().state.wallet + const translate = useTranslate() - const { id, params } = proposal - const { proposer, requiredNamespaces, optionalNamespaces } = params + const { id, params } = proposal + const { proposer, requiredNamespaces, optionalNamespaces } = params - const [isLoading, setIsLoading] = useState(false) - const [selectedAccountIds, setSelectedAccountIds] = useState([]) - const toggleAccountId = useCallback((accountId: string) => { - setSelectedAccountIds(previousState => - previousState.includes(accountId) - ? previousState.filter(existingAccountId => existingAccountId !== accountId) - : [...previousState, accountId], - ) - }, []) + const [isLoading, setIsLoading] = useState(false) + const [selectedAccountIds, setSelectedAccountIds] = useState([]) + const toggleAccountId = useCallback((accountId: string) => { + setSelectedAccountIds(previousState => + previousState.includes(accountId) + ? previousState.filter(existingAccountId => existingAccountId !== accountId) + : [...previousState, accountId], + ) + }, []) - /* + /* We need to pass an account for every supported namespace. If we can't, we cannot approve the session. https://docs.walletconnect.com/2.0/specs/clients/sign/session-namespaces#21-session-namespaces-must-not-have-accounts-empty */ - const allNamespacesSupported = useMemo(() => { - const allRequiredNamespacesSupported = checkAllNamespacesSupported(requiredNamespaces, wallet) - return allRequiredNamespacesSupported - }, [requiredNamespaces, wallet]) + const allNamespacesSupported = useMemo(() => { + const allRequiredNamespacesSupported = checkAllNamespacesSupported(requiredNamespaces, wallet) + return allRequiredNamespacesSupported + }, [requiredNamespaces, wallet]) - /* + /* All namespaces require at least one account in the response payload https://docs.walletconnect.com/2.0/specs/clients/sign/session-namespaces#24-session-namespaces-must-contain-at-least-one-account-in-requested-chains */ - const allNamespacesHaveAccounts = useMemo(() => { - const allRequiredNamespacesHaveAccounts = checkAllNamespacesHaveAccounts( - requiredNamespaces, - selectedAccountIds, - ) - return allRequiredNamespacesHaveAccounts - }, [requiredNamespaces, selectedAccountIds]) + const allNamespacesHaveAccounts = useMemo(() => { + const allRequiredNamespacesHaveAccounts = checkAllNamespacesHaveAccounts( + requiredNamespaces, + selectedAccountIds, + ) + return allRequiredNamespacesHaveAccounts + }, [requiredNamespaces, selectedAccountIds]) + + const supportedOptionalNamespacesWithAccounts = useMemo(() => { + return Object.fromEntries( + Object.entries(optionalNamespaces) + .map(([key, namespace]): [string, ProposalTypes.BaseRequiredNamespace] => { + namespace.chains = namespace.chains?.filter(chainId => { + const isRequired = requiredNamespaces[key].chains?.includes(chainId) + const isSupported = walletSupportsChain({ chainId, wallet, isSnapInstalled: false }) + return !isRequired && isSupported + }) - const supportedOptionalNamespacesWithAccounts = useMemo(() => { - return Object.fromEntries( - Object.entries(optionalNamespaces) - .map(([key, namespace]): [string, ProposalTypes.BaseRequiredNamespace] => { - namespace.chains = namespace.chains?.filter(chainId => { - const isRequired = requiredNamespaces[key].chains?.includes(chainId) - const isSupported = walletSupportsChain({ chainId, wallet, isSnapInstalled: false }) - return !isRequired && isSupported + return [key, namespace] }) + .filter(([_key, namespace]) => { + return namespace.chains && namespace.chains.length > 0 + }), + ) + }, [optionalNamespaces, requiredNamespaces, wallet]) - return [key, namespace] - }) - .filter(([_key, namespace]) => { - return namespace.chains && namespace.chains.length > 0 - }), + const approvalNamespaces: SessionTypes.Namespaces = createApprovalNamespaces( + requiredNamespaces, + selectedAccountIds, ) - }, [optionalNamespaces, requiredNamespaces, wallet]) - const approvalNamespaces: SessionTypes.Namespaces = createApprovalNamespaces( - requiredNamespaces, - selectedAccountIds, - ) + const handleApprove = useCallback(async () => { + // exit if the proposal was not found - likely duplicate call rerendering shenanigans + const pendingProposals = web3wallet.getPendingSessionProposals() + if ( + !Object.values(pendingProposals).some(pendingProposal => pendingProposal.id === proposal.id) + ) { + return + } - const handleApprove = useCallback(async () => { - // exit if the proposal was not found - likely duplicate call rerendering shenanigans - const pendingProposals = web3wallet.getPendingSessionProposals() - if ( - !Object.values(pendingProposals).some(pendingProposal => pendingProposal.id === proposal.id) - ) { - return - } + setIsLoading(true) - setIsLoading(true) + const session = await web3wallet.approveSession({ + id: proposal.id, + namespaces: approvalNamespaces, + }) + dispatch({ type: WalletConnectActionType.ADD_SESSION, payload: session }) + handleClose() + }, [approvalNamespaces, dispatch, handleClose, proposal, web3wallet]) - const session = await web3wallet.approveSession({ - id: proposal.id, - namespaces: approvalNamespaces, - }) - dispatch({ type: WalletConnectActionType.ADD_SESSION, payload: session }) - handleClose() - }, [approvalNamespaces, dispatch, handleClose, proposal, web3wallet]) + const handleReject = useCallback(async () => { + setIsLoading(true) - const handleReject = useCallback(async () => { - setIsLoading(true) + await web3wallet.rejectSession({ + id, + reason: getSdkError('USER_REJECTED_METHODS'), + }) + }, [id, web3wallet]) - await web3wallet.rejectSession({ - id, - reason: getSdkError('USER_REJECTED_METHODS'), - }) + const handleRejectAndClose = useCallback(async () => { + await handleReject() + handleClose() + }, [handleClose, handleReject]) - handleClose() - }, [handleClose, id, web3wallet]) + // pass a reference to the reject function to the modal manager so it can reject on close + useImperativeHandle(ref, () => ({ + handleReject, + })) - const modalBody: JSX.Element = useMemo(() => { - return allNamespacesSupported ? ( - <> - - - - - - - - - - {Object.keys(supportedOptionalNamespacesWithAccounts).length > 0 && ( - - + const modalBody: JSX.Element = useMemo(() => { + return allNamespacesSupported ? ( + <> + + - + - )} + {Object.keys(supportedOptionalNamespacesWithAccounts).length > 0 && ( + + + + + + + + + + )} + + ) : ( + + {translate('plugins.walletConnectToDapps.modal.sessionProposal.unsupportedChain')} + + ) + }, [ + allNamespacesSupported, + requiredNamespaces, + selectedAccountIds, + toggleAccountId, + supportedOptionalNamespacesWithAccounts, + allNamespacesHaveAccounts, + translate, + ]) + + return ( + <> + + + + {modalBody} + + + + + + - ) : ( - - {translate('plugins.walletConnectToDapps.modal.sessionProposal.unsupportedChain')} - ) - }, [ - allNamespacesSupported, - requiredNamespaces, - selectedAccountIds, - toggleAccountId, - supportedOptionalNamespacesWithAccounts, - allNamespacesHaveAccounts, - translate, - ]) - - return ( - <> - - - - {modalBody} - - - - - - - - ) -} + }, +) export const SessionProposalModal = SessionProposal diff --git a/src/plugins/walletConnectToDapps/types.ts b/src/plugins/walletConnectToDapps/types.ts index ba172cd176f..58a4edf525e 100644 --- a/src/plugins/walletConnectToDapps/types.ts +++ b/src/plugins/walletConnectToDapps/types.ts @@ -240,3 +240,7 @@ export type ConfirmData = { priorityFee: string } } + +export type SessionProposalRef = { + handleReject: () => Promise +} From e1f4d8509e14afd43ad09476958b79f2e732fef6 Mon Sep 17 00:00:00 2001 From: woody <125113430+woodenfurniture@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:22:17 +1100 Subject: [PATCH 06/10] fix: ensure wallet connected when wallectconnect receives a request (#5387) --- .../walletConnectToDapps/WalletConnectModalManager.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx b/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx index 89a00fcc311..d8d60b11744 100644 --- a/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx +++ b/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx @@ -77,7 +77,7 @@ export const WalletConnectModalManager: FC = ({ state, dispatch, }) => { - const wallet = useWallet().state.wallet + const { wallet, isConnected } = useWallet().state const sessionProposalRef = useRef(null) const { chainAdapter, requestEvent, accountMetadata, accountId } = useWalletConnectState(state) @@ -265,6 +265,12 @@ export const WalletConnectModalManager: FC = ({ web3wallet, ]) + // automatically reject requests that are received without wallet connected + if (!isConnected) { + void handleRejectRequestAndClose() + return null + } + if (modalContent === null) return null return ( From 4e0571cd05fa319b4ccf89ff7cdff2be16c793e8 Mon Sep 17 00:00:00 2001 From: Apotheosis <0xapotheosis@gmail.com> Date: Tue, 3 Oct 2023 12:35:58 +1100 Subject: [PATCH 07/10] =?UTF-8?q?revert:=20fix:=20ensure=20wallet=20connec?= =?UTF-8?q?ted=20when=20wallectconnect=20receives=20a=20r=E2=80=A6=20(#538?= =?UTF-8?q?9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit revert: fix: ensure wallet connected when wallectconnect receives a request (#5387) This reverts commit e1f4d8509e14afd43ad09476958b79f2e732fef6. --- .../walletConnectToDapps/WalletConnectModalManager.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx b/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx index d8d60b11744..89a00fcc311 100644 --- a/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx +++ b/src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx @@ -77,7 +77,7 @@ export const WalletConnectModalManager: FC = ({ state, dispatch, }) => { - const { wallet, isConnected } = useWallet().state + const wallet = useWallet().state.wallet const sessionProposalRef = useRef(null) const { chainAdapter, requestEvent, accountMetadata, accountId } = useWalletConnectState(state) @@ -265,12 +265,6 @@ export const WalletConnectModalManager: FC = ({ web3wallet, ]) - // automatically reject requests that are received without wallet connected - if (!isConnected) { - void handleRejectRequestAndClose() - return null - } - if (modalContent === null) return null return ( From e4c190db2ae5b5190465b7d32c7aff183f439406 Mon Sep 17 00:00:00 2001 From: Apotheosis <0xapotheosis@gmail.com> Date: Tue, 3 Oct 2023 12:44:44 +1100 Subject: [PATCH 08/10] feat: turn on wcv2 wallet support (#5388) * feat: turn on wcv2 wallet support * chore: remove "v2" --- .env.base | 2 +- .env.dev | 1 - .env.develop | 1 - src/context/WalletProvider/WalletConnectV2/config.ts | 2 +- src/plugins/walletConnectToDapps/WalletConnectV2Provider.tsx | 2 +- 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.env.base b/.env.base index b02e21f17ce..d454c30b731 100644 --- a/.env.base +++ b/.env.base @@ -23,7 +23,7 @@ REACT_APP_FEATURE_NFT_METADATA=false REACT_APP_FEATURE_CHATWOOT=false REACT_APP_FEATURE_COINBASE_WALLET=true REACT_APP_FEATURE_ADVANCED_SLIPPAGE=true -REACT_APP_FEATURE_WALLET_CONNECT_V2=false +REACT_APP_FEATURE_WALLET_CONNECT_V2=true REACT_APP_FEATURE_FOX_DISCOUNTS=false # absolute URL prefix diff --git a/.env.dev b/.env.dev index 6390ddd9516..59f5992e840 100644 --- a/.env.dev +++ b/.env.dev @@ -1,6 +1,5 @@ # feature flags REACT_APP_FEATURE_NFT_METADATA=true -REACT_APP_FEATURE_WALLET_CONNECT_V2=true REACT_APP_FEATURE_FOX_DISCOUNTS=true # logging diff --git a/.env.develop b/.env.develop index 640e88b9218..a6d48f1d562 100644 --- a/.env.develop +++ b/.env.develop @@ -1,7 +1,6 @@ # feature flags REACT_APP_FEATURE_NFT_METADATA=true REACT_APP_FEATURE_CHATWOOT=true -REACT_APP_FEATURE_WALLET_CONNECT_V2=true # mixpanel REACT_APP_MIXPANEL_TOKEN=1c1369f6ea23a6404bac41b42817cc4b diff --git a/src/context/WalletProvider/WalletConnectV2/config.ts b/src/context/WalletProvider/WalletConnectV2/config.ts index 956d0e1968e..baa0910759f 100644 --- a/src/context/WalletProvider/WalletConnectV2/config.ts +++ b/src/context/WalletProvider/WalletConnectV2/config.ts @@ -10,7 +10,7 @@ export const WalletConnectV2Config: Omit = { adapters: [WalletConnectV2Adapter], supportsMobile: 'both', icon: WalletConnectIcon, - name: 'WalletConnectV2', + name: 'WalletConnect', description: 'v2', } diff --git a/src/plugins/walletConnectToDapps/WalletConnectV2Provider.tsx b/src/plugins/walletConnectToDapps/WalletConnectV2Provider.tsx index 3e93681480d..c7895e9ef99 100644 --- a/src/plugins/walletConnectToDapps/WalletConnectV2Provider.tsx +++ b/src/plugins/walletConnectToDapps/WalletConnectV2Provider.tsx @@ -59,7 +59,7 @@ export const WalletConnectV2Provider: FC = ({ children }) => useEffect(() => { // If we are connected to a wallet via wallet connect then this logic does not apply. - if (walletInfo?.name === 'WalletConnectV2') return + if (walletInfo?.name === 'WalletConnect') return // NOTE: don't use `useAppSelector(selectWalletId)` because it introduces a race condition const deviceId = walletInfo?.deviceId From dc94f2c857c82388b09d18c13c226592a9e1f1a7 Mon Sep 17 00:00:00 2001 From: Apotheosis <97164662+0xApotheosis@users.noreply.github.com> Date: Tue, 3 Oct 2023 17:38:45 +1100 Subject: [PATCH 09/10] chore: disable wallet connect in production --- .env.base | 2 +- .env.dev | 1 + .env.develop | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.env.base b/.env.base index d454c30b731..b02e21f17ce 100644 --- a/.env.base +++ b/.env.base @@ -23,7 +23,7 @@ REACT_APP_FEATURE_NFT_METADATA=false REACT_APP_FEATURE_CHATWOOT=false REACT_APP_FEATURE_COINBASE_WALLET=true REACT_APP_FEATURE_ADVANCED_SLIPPAGE=true -REACT_APP_FEATURE_WALLET_CONNECT_V2=true +REACT_APP_FEATURE_WALLET_CONNECT_V2=false REACT_APP_FEATURE_FOX_DISCOUNTS=false # absolute URL prefix diff --git a/.env.dev b/.env.dev index 59f5992e840..094fea9e881 100644 --- a/.env.dev +++ b/.env.dev @@ -1,6 +1,7 @@ # feature flags REACT_APP_FEATURE_NFT_METADATA=true REACT_APP_FEATURE_FOX_DISCOUNTS=true +REACT_APP_FEATURE_WALLET_CONNECT_V2=true # logging REACT_APP_REDUX_WINDOW=false diff --git a/.env.develop b/.env.develop index a6d48f1d562..640e88b9218 100644 --- a/.env.develop +++ b/.env.develop @@ -1,6 +1,7 @@ # feature flags REACT_APP_FEATURE_NFT_METADATA=true REACT_APP_FEATURE_CHATWOOT=true +REACT_APP_FEATURE_WALLET_CONNECT_V2=true # mixpanel REACT_APP_MIXPANEL_TOKEN=1c1369f6ea23a6404bac41b42817cc4b From b161eed9174f15e12a761fbe89f80fe7f44c36e3 Mon Sep 17 00:00:00 2001 From: Apotheosis <97164662+0xApotheosis@users.noreply.github.com> Date: Tue, 3 Oct 2023 17:40:00 +1100 Subject: [PATCH 10/10] chore: roll back KeepKey package bumps --- package.json | 4 ++-- yarn.lock | 40 +++++++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index d74c463dfc0..ed9ab68ae96 100644 --- a/package.json +++ b/package.json @@ -95,8 +95,8 @@ "@shapeshiftoss/errors": "workspace:^", "@shapeshiftoss/hdwallet-coinbase": "1.51.0", "@shapeshiftoss/hdwallet-core": "1.51.0", - "@shapeshiftoss/hdwallet-keepkey": "1.51.0", - "@shapeshiftoss/hdwallet-keepkey-webusb": "1.51.0", + "@shapeshiftoss/hdwallet-keepkey": "1.50.10", + "@shapeshiftoss/hdwallet-keepkey-webusb": "1.50.10", "@shapeshiftoss/hdwallet-keplr": "1.51.0", "@shapeshiftoss/hdwallet-metamask": "1.51.0", "@shapeshiftoss/hdwallet-native": "1.51.0", diff --git a/yarn.lock b/yarn.lock index 9092ca47d13..68243e58f34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7813,6 +7813,20 @@ __metadata: languageName: node linkType: hard +"@shapeshiftoss/hdwallet-core@npm:1.50.10": + version: 1.50.10 + resolution: "@shapeshiftoss/hdwallet-core@npm:1.50.10" + dependencies: + "@shapeshiftoss/proto-tx-builder": ^0.8.0 + eip-712: ^1.0.0 + eventemitter2: ^5.0.1 + lodash: ^4.17.21 + rxjs: ^6.4.0 + type-assertions: ^1.1.0 + checksum: f092f731feaa7d729c73ba43b2d3a5828d9f41ec774f9e3ba40ecd870134afb409c3d1184247cb30cba95cf60775d4b64d4b654270d1de7cf16d15af325750c8 + languageName: node + linkType: hard + "@shapeshiftoss/hdwallet-core@npm:1.50.4, @shapeshiftoss/hdwallet-core@npm:^1.50.4": version: 1.50.4 resolution: "@shapeshiftoss/hdwallet-core@npm:1.50.4" @@ -7841,25 +7855,25 @@ __metadata: languageName: node linkType: hard -"@shapeshiftoss/hdwallet-keepkey-webusb@npm:1.51.0": - version: 1.51.0 - resolution: "@shapeshiftoss/hdwallet-keepkey-webusb@npm:1.51.0" +"@shapeshiftoss/hdwallet-keepkey-webusb@npm:1.50.10": + version: 1.50.10 + resolution: "@shapeshiftoss/hdwallet-keepkey-webusb@npm:1.50.10" dependencies: - "@shapeshiftoss/hdwallet-core": 1.51.0 - "@shapeshiftoss/hdwallet-keepkey": 1.51.0 - checksum: 597ac519d1d9466d17f8074aab04310ee8bb10dabe97f7631b879c15b347dc1b8a0c0b03c45ed3024fab40fc12b87cfdc92ee0786ab051000979c585ac0ebbac + "@shapeshiftoss/hdwallet-core": 1.50.10 + "@shapeshiftoss/hdwallet-keepkey": 1.50.10 + checksum: 32e5a665d75a522aa40984a28508fac84af4b3e6d053a7f741afda038b2f9920bb9d6d2411a60e024065009865f3d85a88a3c6864266178ac4be7e9681885d97 languageName: node linkType: hard -"@shapeshiftoss/hdwallet-keepkey@npm:1.51.0": - version: 1.51.0 - resolution: "@shapeshiftoss/hdwallet-keepkey@npm:1.51.0" +"@shapeshiftoss/hdwallet-keepkey@npm:1.50.10": + version: 1.50.10 + resolution: "@shapeshiftoss/hdwallet-keepkey@npm:1.50.10" dependencies: "@ethereumjs/common": ^2.4.0 "@ethereumjs/tx": ^3.3.0 "@keepkey/device-protocol": ^7.12.2 "@shapeshiftoss/bitcoinjs-lib": 5.2.0-shapeshift.2 - "@shapeshiftoss/hdwallet-core": 1.51.0 + "@shapeshiftoss/hdwallet-core": 1.50.10 "@shapeshiftoss/proto-tx-builder": ^0.8.0 bignumber.js: ^9.0.1 bnb-javascript-sdk-nobroadcast: ^2.16.14 @@ -7872,7 +7886,7 @@ __metadata: p-lazy: ^3.1.0 semver: ^7.3.8 tiny-secp256k1: ^1.1.6 - checksum: ca3d0d19fdb48dc3c08d3a0e3f12e9c675d853f88a6ddc1c8404fe15e0c83a0f1ae5e672c985b29e271c30ee70f8812de3fe21ab29ce6f780b8f162c79c71282 + checksum: 95f8f18cf3792e8de25d83339d38c72be9f518fec369b1986f3b11b8691b47d0d97e5134f8cf7a5c7015c80d3b27af273ce0be9453003ab4d9b545bc9d375219 languageName: node linkType: hard @@ -8188,8 +8202,8 @@ __metadata: "@shapeshiftoss/errors": "workspace:^" "@shapeshiftoss/hdwallet-coinbase": 1.51.0 "@shapeshiftoss/hdwallet-core": 1.51.0 - "@shapeshiftoss/hdwallet-keepkey": 1.51.0 - "@shapeshiftoss/hdwallet-keepkey-webusb": 1.51.0 + "@shapeshiftoss/hdwallet-keepkey": 1.50.10 + "@shapeshiftoss/hdwallet-keepkey-webusb": 1.50.10 "@shapeshiftoss/hdwallet-keplr": 1.51.0 "@shapeshiftoss/hdwallet-metamask": 1.51.0 "@shapeshiftoss/hdwallet-native": 1.51.0