From 2b3bcfd26cf6e6d2311b05323a7bbca40dbaa807 Mon Sep 17 00:00:00 2001 From: Liviu Ciulinaru Date: Thu, 28 Nov 2024 13:58:02 +0700 Subject: [PATCH] feat: clean up old swap feature flags feat: rm legacy code fix: borken tests fix: rm unused hooks fix: tsc fix: unsuned import fix: rm unused files fix: rm legacy swap lld code chore: pr comments --- .changeset/tricky-dryers-check.md | 7 + .../src/renderer/analytics/segment.ts | 18 +- .../renderer/components/AnimatedCountdown.tsx | 37 -- .../swap-migrations/useSwapLiveAppHook.tsx | 108 ---- .../src/renderer/icons/ArrowsUpDown.tsx | 16 - .../Exchange/CompleteExchange/Body.tsx | 19 +- .../screens/exchange/Swap2/App/App.tsx | 9 +- .../exchange/Swap2/Form/DrawerTitle.tsx | 18 - .../Swap2/Form/ExchangeDrawer/SwapAction.tsx | 183 ------ .../Swap2/Form/ExchangeDrawer/index.tsx | 246 -------- .../exchange/Swap2/Form/FeesDrawer/index.tsx | 78 --- .../Swap2/Form/FormRates/ProvidersSection.tsx | 15 - .../Swap2/Form/FormRates/SectionRate.tsx | 40 -- .../exchange/Swap2/Form/FormRates/index.tsx | 37 -- .../exchange/Swap2/Form/FormRates/types.ts | 12 - .../Swap2/Form/FormSelectors/FormInputs.tsx | 140 ----- .../Swap2/Form/FormSelectors/FormLabel.tsx | 10 - .../Swap2/Form/FormSelectors/FromRow.tsx | 242 -------- .../Swap2/Form/FormSelectors/ToRow.tsx | 153 ----- .../Swap2/Form/FormSelectors/index.ts | 1 - .../Swap2/Form/FormSelectors/utils.tsx | 41 -- .../Swap2/Form/FormSummary/SectionFees.tsx | 193 ------ .../Form/FormSummary/SectionInformative.tsx | 54 -- .../Swap2/Form/FormSummary/SectionTarget.tsx | 162 ----- .../Swap2/Form/FormSummary/SummaryLabel.tsx | 49 -- .../Swap2/Form/FormSummary/SummarySection.tsx | 19 - .../Swap2/Form/FormSummary/SummaryValue.tsx | 69 --- .../exchange/Swap2/Form/FormSummary/index.tsx | 82 --- .../exchange/Swap2/Form/FormSummary/types.ts | 12 - .../Swap2/Form/Migrations/SwapMigrationUI.tsx | 124 ---- .../exchange/Swap2/Form/Rates/Countdown.tsx | 45 -- .../exchange/Swap2/Form/Rates/EmptyState.tsx | 25 - .../Swap2/Form/Rates/LoadingState.tsx | 60 -- .../Swap2/Form/Rates/NoQuoteSwapRate.tsx | 44 -- .../exchange/Swap2/Form/Rates/Rate.tsx | 89 --- .../exchange/Swap2/Form/Rates/SwapRate.tsx | 109 ---- .../Swap2/Form/Rates/filterRates.spec.ts | 141 ----- .../exchange/Swap2/Form/Rates/filterRates.ts | 25 - .../exchange/Swap2/Form/Rates/index.tsx | 258 -------- .../Form/Rates/utils/formatCountdown.test.ts | 10 - .../Swap2/Form/Rates/utils/formatCountdown.ts | 5 - .../exchange/Swap2/Form/SwapWebView.tsx | 585 ------------------ .../exchange/Swap2/Form/SwapWebViewDemo3.tsx | 18 +- .../Swap2/Form/TargetAccountDrawer/index.tsx | 286 --------- .../screens/exchange/Swap2/Form/index.tsx | 527 ---------------- .../Swap2/hooks/useIsSwapLiveFlagEnabled.ts | 25 - .../Swap2/hooks/useSwapLiveAppQuoteState.ts | 31 - .../renderer/screens/exchange/Swap2/index.tsx | 8 +- .../src/renderer/screens/swapWeb/index.tsx | 14 +- .../useIsCurrencySupported.ts | 34 - .../useIsSwapLiveApp.test.ts | 53 +- .../live-app-migration/useIsSwapLiveApp.ts | 28 +- .../useSwapLiveConfig.test.ts | 166 +---- .../live-app-migration/useSwapLiveConfig.ts | 43 +- .../swap/hooks/v5/useFilteredProviders.ts | 16 +- .../src/featureFlags/defaultFeatures.ts | 30 +- .../packages/types-live/src/feature.ts | 21 +- 57 files changed, 67 insertions(+), 4823 deletions(-) create mode 100644 .changeset/tricky-dryers-check.md delete mode 100644 apps/ledger-live-desktop/src/renderer/components/AnimatedCountdown.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/hooks/swap-migrations/useSwapLiveAppHook.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/icons/ArrowsUpDown.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/DrawerTitle.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/SwapAction.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/index.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FeesDrawer/index.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/ProvidersSection.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/SectionRate.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/index.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/types.ts delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FormInputs.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FormLabel.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FromRow.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/ToRow.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/index.ts delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/utils.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionFees.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionInformative.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionTarget.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummaryLabel.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummarySection.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummaryValue.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/index.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/types.ts delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Migrations/SwapMigrationUI.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Countdown.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/EmptyState.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/LoadingState.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/NoQuoteSwapRate.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Rate.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/SwapRate.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/filterRates.spec.ts delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/filterRates.ts delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/index.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/utils/formatCountdown.test.ts delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/utils/formatCountdown.ts delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/SwapWebView.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/TargetAccountDrawer/index.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/hooks/useIsSwapLiveFlagEnabled.ts delete mode 100644 apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/hooks/useSwapLiveAppQuoteState.ts delete mode 100644 libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsCurrencySupported.ts diff --git a/.changeset/tricky-dryers-check.md b/.changeset/tricky-dryers-check.md new file mode 100644 index 000000000000..aaa78da83fd6 --- /dev/null +++ b/.changeset/tricky-dryers-check.md @@ -0,0 +1,7 @@ +--- +"@ledgerhq/types-live": patch +"ledger-live-desktop": patch +"@ledgerhq/live-common": patch +--- + +remove legacy swap code on LLD diff --git a/apps/ledger-live-desktop/src/renderer/analytics/segment.ts b/apps/ledger-live-desktop/src/renderer/analytics/segment.ts index 079074319398..a6acf0eb6ed2 100644 --- a/apps/ledger-live-desktop/src/renderer/analytics/segment.ts +++ b/apps/ledger-live-desktop/src/renderer/analytics/segment.ts @@ -99,16 +99,6 @@ const getPtxAttributes = () => { const fetchAdditionalCoins = analyticsFeatureFlagMethod("fetchAdditionalCoins"); const stakingProviders = analyticsFeatureFlagMethod("ethStakingProviders"); const ptxCard = analyticsFeatureFlagMethod("ptxCard"); - const ptxSwapMoonpayProviderFlag = analyticsFeatureFlagMethod("ptxSwapMoonpayProvider"); - - const ptxSwapLiveAppDemoZero = analyticsFeatureFlagMethod("ptxSwapLiveAppDemoZero")?.enabled; - const ptxSwapLiveAppDemoOne = analyticsFeatureFlagMethod("ptxSwapLiveAppDemoOne")?.enabled; - const ptxSwapLiveAppDemoThree = analyticsFeatureFlagMethod("ptxSwapLiveAppDemoThree")?.enabled; - const ptxSwapExodusProvider = analyticsFeatureFlagMethod("ptxSwapExodusProvider")?.enabled; - const ptxSwapCoreExperimentFlag = analyticsFeatureFlagMethod("ptxSwapCoreExperiment"); - const ptxSwapCoreExperiment = ptxSwapCoreExperimentFlag?.enabled - ? ptxSwapCoreExperimentFlag?.params?.variant - : undefined; const isBatch1Enabled: boolean = !!fetchAdditionalCoins?.enabled && fetchAdditionalCoins?.params?.batch === 1; @@ -122,19 +112,13 @@ const getPtxAttributes = () => { stakingProviders?.params?.listProvider?.length > 0 ? stakingProviders?.params?.listProvider.length : "flag not loaded"; - const ptxSwapMoonpayProviderEnabled: boolean = !!ptxSwapMoonpayProviderFlag?.enabled; + return { isBatch1Enabled, isBatch2Enabled, isBatch3Enabled, stakingProvidersEnabled, ptxCard, - ptxSwapMoonpayProviderEnabled, - ptxSwapLiveAppDemoZero, - ptxSwapLiveAppDemoOne, - ptxSwapLiveAppDemoThree, - ptxSwapCoreExperiment, - ptxSwapExodusProvider, }; }; diff --git a/apps/ledger-live-desktop/src/renderer/components/AnimatedCountdown.tsx b/apps/ledger-live-desktop/src/renderer/components/AnimatedCountdown.tsx deleted file mode 100644 index 05e5714226a2..000000000000 --- a/apps/ledger-live-desktop/src/renderer/components/AnimatedCountdown.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { memo } from "react"; -import styled from "styled-components"; - -const WrappedSvg = styled.svg` - transform: rotate(-90deg); - border-radius: 50%; - background-clip: padding-box; -`; - -type Props = { - size: number; - bgColor?: string; - fillColor?: string; - duration?: number; -}; -const AnimatedCountdown = ({ - size = 10, - bgColor = "#8A9199", - fillColor = "white", - duration = 60000, -}: Props) => { - return ( - - - - - - - ); -}; -export default memo(AnimatedCountdown); diff --git a/apps/ledger-live-desktop/src/renderer/hooks/swap-migrations/useSwapLiveAppHook.tsx b/apps/ledger-live-desktop/src/renderer/hooks/swap-migrations/useSwapLiveAppHook.tsx deleted file mode 100644 index 7fcc3a521cfe..000000000000 --- a/apps/ledger-live-desktop/src/renderer/hooks/swap-migrations/useSwapLiveAppHook.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { getFeesCurrency, getMainAccount } from "@ledgerhq/live-common/account/index"; -import { formatCurrencyUnit } from "@ledgerhq/live-common/currencies/index"; -import { SwapTransactionType } from "@ledgerhq/live-common/exchange/swap/types"; -import { getProviderName } from "@ledgerhq/live-common/exchange/swap/utils/index"; -import { accountToWalletAPIAccount } from "@ledgerhq/live-common/wallet-api/converters"; -import { getEnv } from "@ledgerhq/live-env"; -import BigNumber from "bignumber.js"; -import isEqual from "lodash/isEqual"; -import { useEffect, useMemo, useRef } from "react"; -import { useSelector } from "react-redux"; -import { rateSelector } from "~/renderer/actions/swap"; -import { walletSelector } from "~/renderer/reducers/wallet"; -import { - SwapProps, - SwapWebManifestIDs, - SwapWebProps, -} from "~/renderer/screens/exchange/Swap2/Form/SwapWebView"; -import { useMaybeAccountUnit } from "../useAccountUnit"; - -export type UseSwapLiveAppHookProps = { - manifestID?: string; - isSwapLiveAppEnabled: boolean; - swapTransaction: SwapTransactionType; - swapError?: Error; - updateSwapWebProps: React.Dispatch | undefined>>; - getExchangeSDKParams: () => Partial; - getProviderRedirectURLSearch: () => URLSearchParams; -}; - -const SWAP_API_BASE = getEnv("SWAP_API_BASE"); - -export const useSwapLiveAppHook = (props: UseSwapLiveAppHookProps) => { - const { - isSwapLiveAppEnabled, - manifestID, - swapTransaction, - swapError, - updateSwapWebProps, - getExchangeSDKParams, - getProviderRedirectURLSearch, - } = props; - const exchangeRate = useSelector(rateSelector); - const provider = exchangeRate?.provider; - const exchangeRatesState = swapTransaction.swap?.rates; - const swapWebPropsRef = useRef(undefined); - const mainFromAccount = - swapTransaction.swap.from.account && - getMainAccount(swapTransaction.swap.from.account, swapTransaction.swap.from.parentAccount); - const estimatedFeesUnit = mainFromAccount && getFeesCurrency(mainFromAccount); - - const unit = useMaybeAccountUnit(mainFromAccount); - const estimatedFees = useMemo(() => { - return unit && BigNumber(formatCurrencyUnit(unit, swapTransaction.status.estimatedFees)); - }, [swapTransaction.status.estimatedFees, unit]); - - const walletState = useSelector(walletSelector); - - useEffect(() => { - if (isSwapLiveAppEnabled) { - const providerRedirectURLSearch = getProviderRedirectURLSearch(); - const { parentAccount: fromParentAccount } = swapTransaction.swap.from; - const fromParentAccountId = fromParentAccount - ? accountToWalletAPIAccount(walletState, fromParentAccount)?.id - : undefined; - const providerRedirectURL = `ledgerlive://discover/${getProviderName( - provider ?? "", - ).toLowerCase()}?${providerRedirectURLSearch.toString()}`; - - let loading = swapTransaction.bridgePending; - - if (manifestID === SwapWebManifestIDs.Demo0) { - loading = swapTransaction.bridgePending || exchangeRatesState.status === "loading"; - } - - const newSwapWebProps = { - provider, - ...getExchangeSDKParams(), - fromParentAccountId, - error: !!swapError, - loading, - providerRedirectURL, - swapApiBase: SWAP_API_BASE, - estimatedFees: estimatedFees?.toString(), - estimatedFeesUnit: estimatedFeesUnit?.id, - }; - - if (!isEqual(newSwapWebProps, swapWebPropsRef.current)) { - swapWebPropsRef.current = newSwapWebProps; - updateSwapWebProps(newSwapWebProps); - } - } - }, [ - walletState, - provider, - manifestID, - isSwapLiveAppEnabled, - getExchangeSDKParams, - getProviderRedirectURLSearch, - swapTransaction.swap.from, - swapTransaction.swap.from.amount, - swapError, - swapTransaction.bridgePending, - exchangeRatesState.status, - updateSwapWebProps, - estimatedFees, - estimatedFeesUnit?.id, - ]); -}; diff --git a/apps/ledger-live-desktop/src/renderer/icons/ArrowsUpDown.tsx b/apps/ledger-live-desktop/src/renderer/icons/ArrowsUpDown.tsx deleted file mode 100644 index 5a1959946298..000000000000 --- a/apps/ledger-live-desktop/src/renderer/icons/ArrowsUpDown.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react"; -const ArrowsUpDown = ({ size = 16, color = "currentColor" }: { size: number; color?: string }) => ( - - - - -); -export default ArrowsUpDown; diff --git a/apps/ledger-live-desktop/src/renderer/modals/Platform/Exchange/CompleteExchange/Body.tsx b/apps/ledger-live-desktop/src/renderer/modals/Platform/Exchange/CompleteExchange/Body.tsx index d57f19560a1c..89c6b60487ff 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/Platform/Exchange/CompleteExchange/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/Platform/Exchange/CompleteExchange/Body.tsx @@ -13,10 +13,17 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react" import { useDispatch } from "react-redux"; import styled from "styled-components"; import { updateAccountWithUpdater } from "~/renderer/actions/accounts"; -import { useIsSwapLiveFlagEnabled } from "~/renderer/screens/exchange/Swap2/hooks/useIsSwapLiveFlagEnabled"; + import { useRedirectToSwapHistory } from "~/renderer/screens/exchange/Swap2/utils"; import { BodyContent } from "./BodyContent"; +export enum ExchangeModeEnum { + Sell = "sell", + Swap = "swap", +} + +export type ExchangeMode = "sell" | "swap"; + export type Data = { provider: string; exchange: Exchange; @@ -32,13 +39,6 @@ export type Data = { magnitudeAwareRate?: BigNumber; }; -export enum ExchangeModeEnum { - Sell = "sell", - Swap = "swap", -} - -export type ExchangeMode = "sell" | "swap"; - type ResultsState = { mode: ExchangeMode; swapId?: string; @@ -195,7 +195,6 @@ const Body = ({ data, onClose }: { data: Data; onClose?: () => void | undefined const handleSellTransaction = (operation: Operation, result: ResultsState) => { handleTransactionResult(result, operation); }; - const isDemo3Enabled = useIsSwapLiveFlagEnabled("ptxSwapLiveAppDemoThree"); const onBroadcastSuccess = useCallback( (operation: Operation) => { @@ -209,7 +208,7 @@ const Body = ({ data, onClose }: { data: Data; onClose?: () => void | undefined const result = getResultByTransactionType(isSwapTransaction); if (getEnv("DISABLE_TRANSACTION_BROADCAST")) { - if (!isSwapTransaction || (isSwapTransaction && !isDemo3Enabled)) { + if (!isSwapTransaction) { const error = new DisabledTransactionBroadcastError(); setError(error); onCancel(error); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/App/App.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/App/App.tsx index ecbb5d8de74b..348c47bf1f8d 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/App/App.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/App/App.tsx @@ -1,4 +1,5 @@ import { useSwapLiveConfig } from "@ledgerhq/live-common/exchange/swap/hooks/index"; +import { DEFAULT_FEATURES } from "@ledgerhq/live-common/featureFlags/index"; import { useRemoteLiveAppManifest } from "@ledgerhq/live-common/platform/providers/RemoteLiveAppProvider/index"; import { useLocalLiveAppManifest } from "@ledgerhq/live-common/wallet-api/LocalLiveAppProvider/index"; import React, { useState } from "react"; @@ -26,10 +27,16 @@ const ErrorWrapper = styled.div` font-weight: 500; `; +// set the default manifest ID for the production swap live app +// in case the FF is failing to load the manifest ID +// "swap-live-app-demo-3" points to production vercel URL for the swap live app +const DEFAULT_MANIFEST_ID = + process.env.DEFAULT_SWAP_MANIFEST_ID || DEFAULT_FEATURES.ptxSwapLiveApp.params?.manifest_id; + export function SwapApp() { const [unavailable, setUnavailable] = useState(false); const swapLiveEnabledFlag = useSwapLiveConfig(); - const swapLiveAppManifestID = swapLiveEnabledFlag?.params?.manifest_id; + const swapLiveAppManifestID = swapLiveEnabledFlag?.params?.manifest_id || DEFAULT_MANIFEST_ID; const localManifest = useLocalLiveAppManifest(swapLiveAppManifestID || undefined); const remoteManifest = useRemoteLiveAppManifest(swapLiveAppManifestID || undefined); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/DrawerTitle.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/DrawerTitle.tsx deleted file mode 100644 index 123bbd9e45a9..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/DrawerTitle.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; -import { Trans } from "react-i18next"; -import Box from "~/renderer/components/Box/Box"; -import { Separator } from "./Separator"; -import Text from "~/renderer/components/Text"; - -export function DrawerTitle({ i18nKey }: { i18nKey: string }) { - return ( - <> - - - - - - - - ); -} diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/SwapAction.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/SwapAction.tsx deleted file mode 100644 index a260b8a66c53..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/SwapAction.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import { getEnv } from "@ledgerhq/live-env"; -import { - ExchangeSwap, - ExchangeRate, - InitSwapResult, - SwapTransaction, - SwapTransactionType, -} from "@ledgerhq/live-common/exchange/swap/types"; -import { useBroadcast } from "@ledgerhq/live-common/hooks/useBroadcast"; -import { createAction as initSwapCreateAction } from "@ledgerhq/live-common/hw/actions/initSwap"; -import { createAction as transactionCreateAction } from "@ledgerhq/live-common/hw/actions/transaction"; -import { Operation, SignedOperation } from "@ledgerhq/types-live"; -import React, { useEffect, useMemo, useRef, useState } from "react"; -import { Trans } from "react-i18next"; -import { useSelector } from "react-redux"; -import BigSpinner from "~/renderer/components/BigSpinner"; -import Box from "~/renderer/components/Box"; -import { mockedEventEmitter } from "~/renderer/components/debug/DebugMock"; -import DeviceAction from "~/renderer/components/DeviceAction"; -import Text from "~/renderer/components/Text"; -import { getCurrentDevice } from "~/renderer/reducers/devices"; -import { mevProtectionSelector } from "~/renderer/reducers/settings"; -import connectApp from "@ledgerhq/live-common/hw/connectApp"; -import initSwap from "@ledgerhq/live-common/exchange/swap/initSwap"; -import { Device } from "@ledgerhq/types-devices"; -import { BigNumber } from "bignumber.js"; - -const transactionAction = transactionCreateAction(getEnv("MOCK") ? mockedEventEmitter : connectApp); -const initAction = initSwapCreateAction( - getEnv("MOCK") ? mockedEventEmitter : connectApp, - getEnv("MOCK") ? mockedEventEmitter : initSwap, -); - -const TransactionResult = ( - props: - | { signedOperation: SignedOperation; device?: Device; swapId?: string | undefined } - | { transactionSignError?: Error }, -) => { - if (!("signedOperation" in props) || !props.signedOperation) return null; - return ( - - - - - - - ); -}; - -type Props = { - swapTransaction: SwapTransactionType; - exchangeRate: ExchangeRate; - onCompletion: (a: { - operation: Operation; - swapId: string; - magnitudeAwareRate: BigNumber; - }) => void; - onError: (a: { error: Error; swapId?: string }) => void; -}; - -export default function SwapAction({ - swapTransaction, - exchangeRate, - onCompletion, - onError, -}: Props) { - const [initData, setInitData] = useState(null); - const [signedOperation, setSignedOperation] = useState(null); - const mevProtected = useSelector(mevProtectionSelector); - const device = useSelector(getCurrentDevice); - const deviceRef = useRef(device); - const { account: fromAccount, parentAccount: fromParentAccount } = swapTransaction.swap.from; - const { account: toAccount, parentAccount: toParentAccount } = swapTransaction.swap.to; - const { transaction, status } = swapTransaction; - const tokenCurrency = - fromAccount && fromAccount.type === "TokenAccount" ? fromAccount.token : null; - - const broadcast = useBroadcast({ - account: fromAccount, - parentAccount: fromParentAccount, - broadcastConfig: { mevProtected }, - }); - - const exchange = useMemo( - () => ({ - fromParentAccount, - fromAccount, - toParentAccount, - toAccount, - }), - [fromAccount, fromParentAccount, toAccount, toParentAccount], - ); - - useEffect(() => { - if (initData && signedOperation) { - const { swapId, magnitudeAwareRate } = initData; - broadcast(signedOperation).then( - operation => { - onCompletion({ - operation, - swapId, - magnitudeAwareRate, - }); - }, - error => { - onError({ - error, - swapId, - }); - }, - ); - } - }, [broadcast, onCompletion, onError, initData, signedOperation]); - - const request = useMemo( - () => ({ - exchange: exchange as ExchangeSwap, - exchangeRate, - transaction: transaction as SwapTransaction, - status, - device: deviceRef, - }), - [exchange, exchangeRate, status, transaction], - ); - - const signRequest = useMemo( - () => ({ - tokenCurrency, - parentAccount: fromParentAccount, - account: fromAccount!, - transaction: initData?.transaction, - appName: "Exchange", - }), - [fromAccount, fromParentAccount, initData?.transaction, tokenCurrency], - ); - - return !initData || !transaction ? ( - { - if ("initSwapError" in result && result.initSwapError) { - onError({ - error: result.initSwapError, - swapId: result.swapId, - }); - } else if ("initSwapResult" in result) { - setInitData(result.initSwapResult); - } - }} - analyticsPropertyFlow="swap" - /> - ) : !signedOperation ? ( - { - if ("transactionSignError" in result) { - onError({ - error: result.transactionSignError, - swapId: initData.swapId, - }); - } else { - setSignedOperation(result.signedOperation); - } - }} - analyticsPropertyFlow="swap" - /> - ) : ( - - ); -} diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/index.tsx deleted file mode 100644 index 1a1318267193..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/index.tsx +++ /dev/null @@ -1,246 +0,0 @@ -import { postSwapCancelled } from "@ledgerhq/live-common/exchange/swap/index"; -import { setBroadcastTransaction } from "@ledgerhq/live-common/exchange/swap/setBroadcastTransaction"; -import { getUpdateAccountWithUpdaterParams } from "@ledgerhq/live-common/exchange/swap/getUpdateAccountWithUpdaterParams"; -import { CompleteExchangeError } from "@ledgerhq/live-common/exchange/error"; -import { - ExchangeSwap, - SwapTransactionType, - ExchangeRate, -} from "@ledgerhq/live-common/exchange/swap/types"; -import React, { useCallback, useMemo, useState } from "react"; -import { Trans } from "react-i18next"; -import { useDispatch, useSelector } from "react-redux"; -import styled from "styled-components"; -import TrackPage from "~/renderer/analytics/TrackPage"; -import { track } from "~/renderer/analytics/segment"; -import { updateAccountWithUpdater } from "~/renderer/actions/accounts"; -import Box from "~/renderer/components/Box"; -import Button from "~/renderer/components/Button"; -import { - Footer as DeviceActionFooter, - Header as DeviceActionHeader, -} from "~/renderer/components/DeviceAction/rendering"; -import ErrorDisplay from "~/renderer/components/ErrorDisplay"; -import { setDrawer } from "~/renderer/drawers/Provider"; -import { useGetSwapTrackingProperties, useRedirectToSwapHistory } from "../../utils/index"; -import { DrawerTitle } from "../DrawerTitle"; -import { Separator } from "../Separator"; -import SwapAction from "./SwapAction"; -import SwapCompleted from "./SwapCompleted"; -import { Operation } from "@ledgerhq/types-live"; -import { BigNumber } from "bignumber.js"; -import { getCurrentDevice } from "~/renderer/reducers/devices"; -import { rateSelector } from "~/renderer/actions/swap"; - -const ContentBox = styled(Box)` - ${DeviceActionHeader} { - flex: 0; - } - ${DeviceActionFooter} { - flex: 0; - } -`; - -type Props = { - swapTransaction: SwapTransactionType; - exchangeRate: ExchangeRate; - onCompleteSwap?: () => void; -}; - -export default function ExchangeDrawer({ swapTransaction, exchangeRate, onCompleteSwap }: Props) { - const dispatch = useDispatch(); - const [error, setError] = useState(null); - const [result, setResult] = useState<{ - operation: Operation; - swapId: string; - } | null>(null); - const swapDefaultTrack = useGetSwapTrackingProperties(); - const device = useSelector(getCurrentDevice); - const selectedExchangeRate = useSelector(rateSelector); - const redirectToHistory = useRedirectToSwapHistory(); - const { - transaction, - swap: { - from: { account: fromAccount, parentAccount: fromParentAccount, currency: sourceCurrency }, - to: { account: toAccount, parentAccount: toParentAccount, currency: targetCurrency }, - }, - } = swapTransaction; - - const exchange = useMemo( - () => ({ - fromParentAccount, - fromAccount, - toParentAccount, - toAccount, - }), - [fromAccount, fromParentAccount, toAccount, toParentAccount], - ) as ExchangeSwap; - - const onError = useCallback( - (errorResult: { error: Error; swapId?: string }) => { - const { error, swapId } = errorResult; - // Consider the swap as cancelled (on provider perspective) in case of error - postSwapCancelled({ - provider: exchangeRate.provider, - swapId: swapId ?? "", - ...((error as CompleteExchangeError).step - ? { swapStep: (error as CompleteExchangeError).step } - : {}), - statusCode: error.name, - errorMessage: error.message, - sourceCurrencyId: swapTransaction.swap.from.currency?.id, - targetCurrencyId: swapTransaction.swap.to.currency?.id, - hardwareWalletType: device?.modelId, - swapType: selectedExchangeRate?.tradeMethod, - }); - track("error_message", { - message: "drawer_error", - page: "Page Swap Drawer", - ...swapDefaultTrack, - error, - }); - setError(error); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [exchangeRate.provider, swapDefaultTrack], - ); - - const onCompletion = useCallback( - ({ - magnitudeAwareRate, - ...result - }: { - operation: Operation; - swapId: string; - magnitudeAwareRate: BigNumber; - }) => { - const { provider } = exchangeRate; - - setBroadcastTransaction({ - result, - provider, - sourceCurrencyId: swapTransaction.swap.from.currency?.id, - targetCurrencyId: swapTransaction.swap.to.currency?.id, - hardwareWalletType: device?.modelId, - swapType: selectedExchangeRate?.tradeMethod, - }); - const params = getUpdateAccountWithUpdaterParams({ - result, - exchange, - transaction, - magnitudeAwareRate, - provider, - }); - if (!params.length) return; - const dispatchAction = updateAccountWithUpdater(...params); - dispatch(dispatchAction); - setResult(result); - onCompleteSwap && onCompleteSwap(); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [dispatch, exchange, exchangeRate, transaction, onCompleteSwap], - ); - - const onViewDetails = useCallback( - () => { - if (!result) return; - const { operation } = result; - const concernedOperation = operation - ? operation.subOperations && operation.subOperations.length > 0 - ? operation.subOperations[0] - : operation - : null; - if (fromAccount && concernedOperation) { - redirectToHistory({ - swapId: result?.swapId, - }); - } - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [fromAccount, fromParentAccount, result?.operation], - ); - - const closeDrawer = useCallback(() => setDrawer(), []); - - if (error) { - return ( - - - - - - - - - - - - - ); - } - if (result) { - return ( - - - {targetCurrency && ( - - - - )} - - - - - - - - ); - } - return ( - - - - - - - ); -} diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FeesDrawer/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FeesDrawer/index.tsx deleted file mode 100644 index d8e26517429c..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FeesDrawer/index.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React, { useCallback } from "react"; -import { useSelector } from "react-redux"; -import Box from "~/renderer/components/Box"; -import SendAmountFields from "~/renderer/modals/Send/SendAmountFields"; -import { transactionSelector } from "~/renderer/actions/swap"; -import { - SwapTransactionType, - SwapSelectorStateType, -} from "@ledgerhq/live-common/exchange/swap/types"; -import { DrawerTitle } from "../DrawerTitle"; -import TrackPage from "~/renderer/analytics/TrackPage"; -import { useGetSwapTrackingProperties } from "../../utils/index"; -import { Account, FeeStrategy } from "@ledgerhq/types-live"; - -type Props = { - setTransaction: SwapTransactionType["setTransaction"]; - updateTransaction: SwapTransactionType["updateTransaction"]; - mainAccount: SwapSelectorStateType["account"]; - parentAccount: SwapSelectorStateType["parentAccount"]; - currency: SwapSelectorStateType["currency"]; - status: SwapTransactionType["status"]; - disableSlowStrategy?: boolean; - provider: string | undefined | null; -}; - -export default function FeesDrawer({ - setTransaction, - updateTransaction, - mainAccount, - parentAccount, - status, - provider, - disableSlowStrategy = false, -}: Props) { - const swapDefaultTrack = useGetSwapTrackingProperties(); - const transaction = useSelector(transactionSelector); - - const mapStrategies = useCallback( - (strategy: FeeStrategy) => - strategy.label === "slow" && disableSlowStrategy - ? { - ...strategy, - disabled: true, - } - : strategy, - [disableSlowStrategy], - ); - - return ( - - - - - {transaction && mainAccount && ( - - )} - - - ); -} diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/ProvidersSection.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/ProvidersSection.tsx deleted file mode 100644 index 1e8131780af1..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/ProvidersSection.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from "react"; -import styled from "styled-components"; - -const Container = styled.div` - display: flex; - flex-direction: row; - justify-content: space-between; - min-height: 20px; -`; -type ProvidersSectionProps = { - children: React.ReactNode; -}; - -const ProvidersSection = ({ children }: ProvidersSectionProps) => {children}; -export default ProvidersSection; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/SectionRate.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/SectionRate.tsx deleted file mode 100644 index a2717986655f..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/SectionRate.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { - RatesReducerState, - SwapSelectorStateType, -} from "@ledgerhq/live-common/exchange/swap/types"; -import React from "react"; -import Rates from "../Rates"; -import ProvidersSection from "./ProvidersSection"; - -export type SectionRateProps = { - provider?: string; - ratesState: RatesReducerState; - fromCurrency: SwapSelectorStateType["currency"]; - toCurrency: SwapSelectorStateType["currency"]; - countdownSecondsToRefresh: number | undefined; -}; - -const SectionRate = ({ - provider, - fromCurrency, - toCurrency, - ratesState, - countdownSecondsToRefresh, -}: SectionRateProps) => { - const rates = ratesState.value; - - return ( - - - - ); -}; -export default React.memo(SectionRate); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/index.tsx deleted file mode 100644 index 3a1a7023c215..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { SwapDataType } from "@ledgerhq/live-common/exchange/swap/types"; -import React from "react"; -import styled from "styled-components"; -import SectionRate from "./SectionRate"; - -const Form = styled.section` - display: grid; - row-gap: 1.375rem; - color: white; -`; -type SwapFormProvidersProps = { - swap: SwapDataType; - countdownSecondsToRefresh: number | undefined; - provider?: string; -}; - -const SwapFormProviders = ({ - swap, - provider, - countdownSecondsToRefresh, -}: SwapFormProvidersProps) => { - const { currency: fromCurrency } = swap.from; - const { currency: toCurrency } = swap.to; - - return ( -
- - - ); -}; -export default React.memo(SwapFormProviders); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/types.ts b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/types.ts deleted file mode 100644 index 82625ce5fe8d..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormRates/types.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { SwapTransactionType } from "@ledgerhq/live-common/exchange/swap/types"; - -export type FormProvidersSections = "provider" | "fees" | "rate" | "target"; -export type FormProvidersProps = { - provider?: string; - rate?: string; - fees?: string; - onProviderChange: Function; - onFeesChange: Function; - onTargetChange: Function; - swapTransaction: SwapTransactionType; -}; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FormInputs.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FormInputs.tsx deleted file mode 100644 index 4ca1d2258d46..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FormInputs.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { - SwapDataType, - SwapSelectorStateType, - SwapTransactionType, -} from "@ledgerhq/live-common/exchange/swap/types"; -import BigNumber from "bignumber.js"; -import React from "react"; -import styled from "styled-components"; -import { track } from "~/renderer/analytics/segment"; -import Box from "~/renderer/components/Box"; -import Button from "~/renderer/components/Button"; -import ArrowsUpDown from "~/renderer/icons/ArrowsUpDown"; -import { useGetSwapTrackingProperties } from "../../utils/index"; -import FromRow from "./FromRow"; -import ToRow from "./ToRow"; - -type FormInputsProps = { - fromAccount: SwapSelectorStateType["account"]; - toAccount: SwapSelectorStateType["account"]; - fromAmount: SwapSelectorStateType["amount"]; - toCurrency: SwapSelectorStateType["currency"]; - toAmount: SwapSelectorStateType["amount"]; - setFromAccount: SwapTransactionType["setFromAccount"]; - setFromAmount: SwapTransactionType["setFromAmount"]; - setToCurrency: SwapTransactionType["setToCurrency"]; - toggleMax: SwapTransactionType["toggleMax"]; - reverseSwap: SwapTransactionType["reverseSwap"]; - isMaxEnabled?: boolean; - fromAmountError?: Error; - fromAmountWarning?: Error; - isSwapReversable: boolean; - provider: string | undefined | null; - loadingRates: boolean; - isSendMaxLoading: boolean; - updateSelectedRate: SwapDataType["updateSelectedRate"]; - counterValue?: BigNumber; -}; - -type SwapButtonProps = { - onClick: SwapTransactionType["reverseSwap"]; - disabled: boolean; -}; - -const RoundButton = styled(Button)` - padding: 8px; - border-radius: 9999px; - height: initial; -`; - -const Main = styled.section` - display: flex; - flex-direction: column; - margin-bottom: 5px; - row-gap: 12px; -`; - -function SwapButton({ onClick, disabled }: SwapButtonProps): JSX.Element { - return ( - - - - ); -} - -export default function FormInputs({ - fromAccount = undefined, - toAccount, - fromAmount = undefined, - isMaxEnabled = false, - setFromAccount, - setFromAmount, - toCurrency, - toAmount, - setToCurrency, - toggleMax, - fromAmountError, - fromAmountWarning, - reverseSwap, - isSwapReversable, - provider, - loadingRates, - isSendMaxLoading, - updateSelectedRate, - counterValue, -}: FormInputsProps) { - const swapDefaultTrack = useGetSwapTrackingProperties(); - const reverseSwapAndTrack = () => { - track("button_clicked2", { - button: "switch", - page: "Page Swap Form", - ...swapDefaultTrack, - }); - reverseSwap(); - }; - - return ( -
- - - - - - - - - -
- ); -} diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FormLabel.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FormLabel.tsx deleted file mode 100644 index 2f87f004bf75..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FormLabel.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from "react"; -import Text from "~/renderer/components/Text"; - -export function FormLabel({ children }: { children?: React.ReactNode }) { - return ( - - {children} - - ); -} diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FromRow.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FromRow.tsx deleted file mode 100644 index 2280c012937b..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FromRow.tsx +++ /dev/null @@ -1,242 +0,0 @@ -import React, { useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import styled from "styled-components"; -import { getAccountCurrency } from "@ledgerhq/live-common/account/index"; -import Box from "~/renderer/components/Box"; -import InputCurrency from "~/renderer/components/InputCurrency"; -import { ErrorContainer } from "~/renderer/components/Input"; -import { SelectAccount } from "~/renderer/components/SelectAccount"; -import Switch from "~/renderer/components/Switch"; -import Text from "~/renderer/components/Text"; -import { amountInputContainerProps, renderAccountValue, selectRowStylesMap } from "./utils"; -import { FormLabel } from "./FormLabel"; -import { - SwapSelectorStateType, - SwapTransactionType, - SwapDataType, -} from "@ledgerhq/live-common/exchange/swap/types"; -import { track } from "~/renderer/analytics/segment"; -import { useGetSwapTrackingProperties } from "../../utils/index"; -import { useCurrenciesByMarketcap } from "@ledgerhq/live-common/currencies/hooks"; -import { listCryptoCurrencies, listTokens } from "@ledgerhq/live-common/currencies/index"; -import { AccountLike } from "@ledgerhq/types-live"; -import BigNumber from "bignumber.js"; -import { TranslatedError } from "~/renderer/components/TranslatedError/TranslatedError"; -import { WarningSolidMedium } from "@ledgerhq/react-ui/assets/icons"; -import { useSwapableAccounts } from "@ledgerhq/live-common/exchange/swap/hooks/index"; -import { useSelector } from "react-redux"; -import { flattenAccountsSelector } from "~/renderer/reducers/accounts"; -import { useMaybeAccountUnit } from "~/renderer/hooks/useAccountUnit"; -import { getDefaultAccountName } from "@ledgerhq/live-wallet/accountName"; - -const SwapStatusContainer = styled.div<{ isError: boolean }>( - ({ theme: { space, colors }, isError }) => ` - margin-top: ${space[1]}px; - display: grid; - grid-template-columns: 16px auto; - align-items: center; - column-gap: ${space[1]}px; - color: ${isError ? colors.error.c70 : colors.warning}; -`, -); - -const SwapStatusText = styled(Text)( - () => ` - & button, a { - text-decoration: underline; - cursor: pointer; - } -`, -); - -/* @dev: Yeah, Im sorry if you read this, design asked us to - override the input component when it is called from the swap form. */ -const InputSection = styled(Box)` - & ${ErrorContainer} { - font-weight: 500; - font-size: 11px; - text-align: right; - margin-left: calc(calc(100% + 30px) * -1); - margin-top: 6px; - align-self: flex-end; - margin-right: -15px; - } -`; - -// Pick a default source account if none are selected. -// TODO use live-common once its ready -const usePickDefaultAccount = ( - accounts: AccountLike[], - fromAccount: AccountLike | undefined, - setFromAccount: (acc?: AccountLike) => void, -): void => { - const list = [...listCryptoCurrencies(), ...listTokens()]; - const allCurrencies = useCurrenciesByMarketcap(list); - useEffect(() => { - if (!fromAccount && allCurrencies.length > 0) { - allCurrencies.some(({ id }) => { - const filteredAcc = accounts.filter( - acc => - getAccountCurrency(acc)?.id === id && - acc.balance.gt(0) && - (!("disabled" in acc) || !acc.disabled), - ); - if (filteredAcc.length > 0) { - const defaultAccount = filteredAcc - .sort((a, b) => b.balance.minus(a.balance).toNumber()) - .find(Boolean); - setFromAccount(defaultAccount); - return true; - } - return false; - }); - } - }, [accounts, allCurrencies, fromAccount, setFromAccount]); -}; - -type Props = { - fromAccount: SwapSelectorStateType["account"]; - setFromAccount: SwapTransactionType["setFromAccount"]; - toggleMax: SwapTransactionType["toggleMax"]; - fromAmount: SwapSelectorStateType["amount"]; - setFromAmount: SwapTransactionType["setFromAmount"]; - isMaxEnabled: boolean; - fromAmountError?: Error; - fromAmountWarning?: Error; - provider: string | undefined | null; - isSendMaxLoading: boolean; - updateSelectedRate: SwapDataType["updateSelectedRate"]; -}; - -function FromRow({ - fromAmount, - setFromAmount, - fromAccount, - setFromAccount, - isMaxEnabled, - toggleMax, - fromAmountError, - fromAmountWarning, - isSendMaxLoading, - updateSelectedRate, -}: Props) { - const swapDefaultTrack = useGetSwapTrackingProperties(); - const flattenedAccounts = useSelector(flattenAccountsSelector); - const accounts = useSwapableAccounts({ accounts: flattenedAccounts }); - const unit = useMaybeAccountUnit(fromAccount); - const { t } = useTranslation(); - usePickDefaultAccount(accounts, fromAccount, setFromAccount); - - if (!fromAccount) return null; - - const trackEditAccount = () => { - track("button_clicked2", { - button: "Edit source account", - page: "Page Swap Form", - ...swapDefaultTrack, - }); - }; - - const setAccountAndTrack = (account: AccountLike) => { - updateSelectedRate(); - const name = account ? getDefaultAccountName(account) : undefined; - track("button_clicked2", { - button: "New source account", - page: "Page Swap Form", - ...swapDefaultTrack, - account: name, - }); - setFromAccount(account); - }; - - const setValue = (fromAmount: BigNumber) => { - track("button_clicked2", { - button: "Amount input", - page: "Page Swap Form", - ...swapDefaultTrack, - amount: null, - }); - updateSelectedRate(); - setFromAmount(fromAmount); - }; - - const toggleMaxAndTrack = (state: unknown) => { - track("button_clicked2", { - button: "max", - page: "Page Swap Form", - ...swapDefaultTrack, - state, - }); - toggleMax(); - }; - - return ( - <> - - {t("swap2.form.from.title")} - - - {t("swap2.form.from.max")} - - - - - - - - - - - - - - {(!!fromAmountError || !!fromAmountWarning) && ( - - - - - - - )} - - ); -} - -export default React.memo(FromRow); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/ToRow.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/ToRow.tsx deleted file mode 100644 index 4a88bcba7fa9..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/ToRow.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { - useFetchCurrencyTo, - usePickDefaultCurrency, - useSelectableCurrencies, -} from "@ledgerhq/live-common/exchange/swap/hooks/index"; -import { - SwapDataType, - SwapSelectorStateType, - SwapTransactionType, -} from "@ledgerhq/live-common/exchange/swap/types"; -import { CryptoOrTokenCurrency } from "@ledgerhq/types-cryptoassets"; -import BigNumber from "bignumber.js"; -import React from "react"; -import { Trans } from "react-i18next"; -import styled from "styled-components"; -import { track } from "~/renderer/analytics/segment"; -import Box from "~/renderer/components/Box/Box"; -import CounterValue from "~/renderer/components/CounterValue"; -import { - BaseContainer as BaseInputContainer, - Container as InputContainer, -} from "~/renderer/components/Input"; -import InputCurrency from "~/renderer/components/InputCurrency"; -import SelectCurrency from "~/renderer/components/SelectCurrency"; -import { useGetSwapTrackingProperties } from "../../utils/index"; -import { FormLabel } from "./FormLabel"; -import { amountInputContainerProps, renderCurrencyValue, selectRowStylesMap } from "./utils"; - -type Props = { - fromAccount: SwapSelectorStateType["account"]; - toAccount: SwapSelectorStateType["account"]; - toCurrency: SwapSelectorStateType["currency"]; - setToCurrency: SwapTransactionType["setToCurrency"]; - toAmount: SwapSelectorStateType["amount"]; - provider: string | undefined | null; - loadingRates: boolean; - updateSelectedRate: SwapDataType["updateSelectedRate"]; - counterValue?: BigNumber; -}; - -const InputCurrencyContainer = styled(Box)` - ${InputContainer} { - display: flex; - background: none; - flex-direction: column; - align-items: flex-end; - justify-content: center; - } - - ${BaseInputContainer} { - flex: 0; - } -`; - -function ToRow({ - toCurrency, - setToCurrency, - toAmount, - fromAccount, - loadingRates, - updateSelectedRate, - counterValue, -}: Props) { - const { data: currenciesTo, isLoading: currenciesToIsLoading } = useFetchCurrencyTo({ - fromCurrencyAccount: fromAccount, - }); - const swapDefaultTrack = useGetSwapTrackingProperties(); - const currencies = useSelectableCurrencies({ - allCurrencies: currenciesTo ?? [], - }); - const unit = toCurrency?.units[0]; - usePickDefaultCurrency(currencies, toCurrency, setToCurrency); - const trackEditCurrency = () => - track("button_clicked2", { - button: "Edit target currency", - page: "Page Swap Form", - ...swapDefaultTrack, - }); - const setCurrencyAndTrack = (currency: CryptoOrTokenCurrency | null | undefined) => { - updateSelectedRate(); - track("button_clicked2", { - button: "New target currency", - page: "Page Swap Form", - ...swapDefaultTrack, - currency: currency?.ticker || currency?.name, - }); - setToCurrency(currency || undefined); - }; - - return ( - <> - - - - - - - - - - - null} - data-testid="destination-currency-amount" - value={unit ? toAmount : null} - disabled - placeholder="-" - textAlign="right" - fontWeight={600} - color="palette.text.shade40" - containerProps={amountInputContainerProps} - unit={unit} - loading={loadingRates} - renderRight={ - toCurrency && - unit && - toAmount && - !loadingRates && ( - - ) - } - /> - - - - ); -} -export default React.memo(ToRow); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/index.ts b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/index.ts deleted file mode 100644 index 562594714958..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./FormInputs"; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/utils.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/utils.tsx deleted file mode 100644 index 9730883893c1..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/utils.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from "react"; -import { CryptoOrTokenCurrency } from "@ledgerhq/types-cryptoassets"; -import { CreateStylesReturnType } from "~/renderer/components/Select/createStyles"; -import { AccountOption, Option as SelectAccountOption } from "~/renderer/components/SelectAccount"; -import { CurrencyOption } from "~/renderer/components/SelectCurrency"; -import { OptionTypeBase } from "react-select"; -import { ThemeConfig } from "react-select/src/theme"; - -export const selectRowStylesMap: ( - a: CreateStylesReturnType & ThemeConfig, -) => CreateStylesReturnType = styles => ({ - ...styles, - control: (provided, state) => ({ - ...styles?.control?.(provided, state), - borderTopRightRadius: 0, - borderBottomRightRadius: 0, - }), - menu: (provided, state) => ({ - ...styles?.menu?.(provided, state), - width: "200%", - }), - valueContainer: (styles: object) => ({ - ...styles, - height: "100%", - }), -}); - -export const amountInputContainerProps = { - noBorderLeftRadius: true, -}; - -export const renderAccountValue = ({ data }: { data: SelectAccountOption }) => - data.account ? ( - - ) : null; - -export const renderCurrencyValue = ({ data: currency }: { data: CryptoOrTokenCurrency }) => { - return currency ? ( - - ) : null; -}; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionFees.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionFees.tsx deleted file mode 100644 index 00bbbd5890af..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionFees.tsx +++ /dev/null @@ -1,193 +0,0 @@ -import React, { useMemo, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { useSelector } from "react-redux"; -import { getMainAccount } from "@ledgerhq/live-common/account/index"; -import { context } from "~/renderer/drawers/Provider"; -import SummaryLabel from "./SummaryLabel"; -import SummaryValue, { NoValuePlaceholder } from "./SummaryValue"; -import SummarySection from "./SummarySection"; -import FeesDrawer from "../FeesDrawer"; -import { - SwapTransactionType, - SwapSelectorStateType, -} from "@ledgerhq/live-common/exchange/swap/types"; -import { track } from "~/renderer/analytics/segment"; -import { rateSelector } from "~/renderer/actions/swap"; -import FormattedVal from "~/renderer/components/FormattedVal"; -import Box from "~/renderer/components/Box"; -import Text from "~/renderer/components/Text"; -import TachometerHigh from "~/renderer/icons/TachometerHigh"; -import TachometerLow from "~/renderer/icons/TachometerLow"; -import TachometerMedium from "~/renderer/icons/TachometerMedium"; -import styled from "styled-components"; -import { useGetSwapTrackingProperties } from "../../utils/index"; -import { EDITABLE_FEE_FAMILIES } from "@ledgerhq/live-common/exchange/swap/const/blockchain"; -import { useMaybeAccountUnit } from "~/renderer/hooks/useAccountUnit"; - -type Strategies = "slow" | "medium" | "fast" | "advanced"; - -const FEES_STRATEGY_ICONS: { - [x in Strategies]: (a: { color?: string; size?: number }) => React.ReactElement<"svg">; -} = { - slow: TachometerLow, - medium: TachometerMedium, - fast: TachometerHigh, - advanced: TachometerHigh, -}; -const IconSection = styled(Box)` - flex-direction: row; - column-gap: 0.25rem; - color: ${props => props.theme.colors.palette.text.shade40}; -`; -const Separator = styled.div` - width: 3px; - height: 3px; - background-color: ${props => props.theme.colors.palette.text.shade40}; - border-radius: 9999px; - align-self: center; - margin-left: 2px; -`; - -type Props = { - transaction: SwapTransactionType["transaction"]; - account: SwapSelectorStateType["account"]; - parentAccount: SwapSelectorStateType["parentAccount"]; - currency: SwapSelectorStateType["currency"]; - status: SwapTransactionType["status"]; - updateTransaction: SwapTransactionType["updateTransaction"]; - setTransaction: SwapTransactionType["setTransaction"]; - provider: string | undefined | null; - hasRates: boolean; -}; - -const SectionFees = ({ - transaction, - account, - parentAccount, - currency, - status, - updateTransaction, - setTransaction, - provider, - hasRates, -}: Props) => { - const { t } = useTranslation(); - const { setDrawer } = React.useContext(context); - const exchangeRate = useSelector(rateSelector); - const mainFromAccount = account && getMainAccount(account, parentAccount); - const mainAccountUnit = useMaybeAccountUnit(mainFromAccount); - const estimatedFees = status?.estimatedFees; - const showSummaryValue = mainFromAccount && estimatedFees && estimatedFees.gt(0); - const family = mainFromAccount?.currency.family; - const canEdit = - hasRates && showSummaryValue && transaction && family && EDITABLE_FEE_FAMILIES.includes(family); - const swapDefaultTrack = useGetSwapTrackingProperties(); - - const StrategyIcon = useMemo( - () => - (transaction?.feesStrategy && - FEES_STRATEGY_ICONS[transaction?.feesStrategy as keyof typeof FEES_STRATEGY_ICONS]) || - undefined, - [transaction?.feesStrategy], - ); - - // Deselect slow strategy if the exchange rate is changed to fixed. - useEffect( - () => { - if (exchangeRate?.tradeMethod === "fixed" && transaction?.feesStrategy === "slow") { - updateTransaction(t => ({ - ...t, - feesStrategy: "medium", - })); - } - }, - // eslint-disable-next-line - [transaction?.feesStrategy, exchangeRate?.tradeMethod, updateTransaction], - ); - - const handleChange = useMemo( - () => - (canEdit && - (() => { - track("button_clicked2", { - button: "change network fees", - page: "Page Swap Form", - ...swapDefaultTrack, - }); - setDrawer( - FeesDrawer, - { - setTransaction, - updateTransaction, - mainAccount: mainFromAccount, - parentAccount: parentAccount, - currency, - status, - disableSlowStrategy: exchangeRate?.tradeMethod === "fixed", - provider, - }, - { - forceDisableFocusTrap: true, - }, - ); - })) || - undefined, - [ - canEdit, - swapDefaultTrack, - setDrawer, - setTransaction, - updateTransaction, - mainFromAccount, - parentAccount, - currency, - status, - exchangeRate?.tradeMethod, - provider, - ], - ); - - const summaryValue = canEdit ? ( - <> - - {StrategyIcon ? : null} - - {t(`fees.${transaction?.feesStrategy ?? "custom"}`)} - - - - - - ) : estimatedFees ? ( - - ) : ( - - ); - - return ( - - - {summaryValue} - - ); -}; - -export default React.memo(SectionFees); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionInformative.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionInformative.tsx deleted file mode 100644 index bfef46709e54..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionInformative.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import { rgba } from "~/renderer/styles/helpers"; -import Button from "~/renderer/components/Button"; -import TextBase from "~/renderer/components/Text"; - -const Container = styled.div` - display: flex; - justify-content: space-between; - background-color: ${p => rgba(p.theme.colors.palette.primary.main, 0.1)}; - color: ${p => p.theme.colors.palette.primary.main}; - column-gap: 0.75rem; - padding: 0.75rem; - border-radius: 4px; - align-items: center; -`; -const Text = styled(TextBase).attrs(() => ({ - ff: "Inter", - fontSize: "0.875rem", - fontWeight: 500, - lineHeight: "1.4", -}))` - &:first-letter { - text-transform: uppercase; - } -`; -const TextWrappper = styled.div` - max-width: 28rem; -`; -const ButtonAddAccount = styled(Button).attrs(() => ({ - primary: true, - small: true, -}))` - height: 40px; -`; - -type SectionInformativeProps = { - message: string; - ctaLabel: string; - onClick: () => void; -}; - -const SectionInformative = ({ message, ctaLabel, onClick }: SectionInformativeProps) => ( - - - {message} - - - {ctaLabel} - - -); - -export default SectionInformative; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionTarget.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionTarget.tsx deleted file mode 100644 index 29400edebe52..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SectionTarget.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import { - SwapSelectorStateType, - SwapTransactionType, -} from "@ledgerhq/live-common/exchange/swap/types"; -import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets"; -import { AccountLike } from "@ledgerhq/types-live"; -import React, { useCallback, useEffect, useRef } from "react"; -import { useTranslation } from "react-i18next"; -import { useDispatch } from "react-redux"; -import { openModal } from "~/renderer/actions/modals"; -import { track } from "~/renderer/analytics/segment"; -import CryptoCurrencyIcon from "~/renderer/components/CryptoCurrencyIcon"; -import { context } from "~/renderer/drawers/Provider"; -import { useMaybeAccountName } from "~/renderer/reducers/wallet"; -import { useGetSwapTrackingProperties } from "../../utils/index"; -import TargetAccountDrawer from "../TargetAccountDrawer"; -import { useIsSwapLiveFlagEnabled } from "../../hooks/useIsSwapLiveFlagEnabled"; -import SectionInformative from "./SectionInformative"; -import SummaryLabel from "./SummaryLabel"; -import SummarySection from "./SummarySection"; -import SummaryValue, { Container, Text, NoValuePlaceholder } from "./SummaryValue"; -import styled from "styled-components"; - -const AccountSectionContainer = styled(SummarySection)` - column-gap: 12px; - display: grid; - grid-template-columns: 1fr 1fr; - - ${Container}, ${Text} { - flex-shrink: 1; - } - - ${Container} ${Text} { - overflow: hidden; - text-overflow: ellipsis; - } -`; - -const AccountSection = ({ - account, - currency, - handleChange, -}: { - account: SwapSelectorStateType["account"]; - currency: TokenCurrency | CryptoCurrency; - handleChange?: () => void; -}) => { - const { t } = useTranslation(); - const accountName = useMaybeAccountName(account); - - const swapDefaultTrack = useGetSwapTrackingProperties(); - - const handleChangeAndTrack = useCallback(() => { - track("button_clicked2", { - button: "change target account", - page: "Page Swap Form", - ...swapDefaultTrack, - }); - - if (handleChange) { - handleChange(); - } - }, [handleChange, swapDefaultTrack]); - - return ( - - - - {currency ? : null} - - - ); -}; - -const PlaceholderSection = () => { - const { t } = useTranslation(); - - return ( - - - - - - - ); -}; - -type SectionTargetProps = { - account: SwapSelectorStateType["account"]; - currency: SwapSelectorStateType["currency"]; - setToAccount: SwapTransactionType["setToAccount"]; - targetAccounts: AccountLike[] | undefined; - hasRates: boolean; -}; - -type SetDrawerStateRef = (args: { - selectedAccount: AccountLike | undefined; - targetAccounts: AccountLike[] | undefined; -}) => void; -const SectionTarget = ({ - account, - currency, - setToAccount, - targetAccounts, - hasRates, -}: SectionTargetProps) => { - const { t } = useTranslation(); - const dispatch = useDispatch(); - const { setDrawer } = React.useContext(context); - const swapDefaultTrack = useGetSwapTrackingProperties(); - const isDemo0Enabled = useIsSwapLiveFlagEnabled("ptxSwapLiveAppDemoZero"); - - const handleAddAccount = () => { - track("button_clicked2", { - button: "add account", - page: "Page Swap Form", - ...swapDefaultTrack, - }); - dispatch(openModal("MODAL_ADD_ACCOUNTS", { currency, ...swapDefaultTrack })); - }; - - const hideEdit = !targetAccounts || targetAccounts.length < 2; - - // Using a ref to keep the drawer state synced. - const setDrawerStateRef = useRef(null); - useEffect(() => { - setDrawerStateRef.current && - setDrawerStateRef.current({ - selectedAccount: account, - targetAccounts, - }); - }, [account, targetAccounts]); - - const showDrawer = () => { - setDrawer(TargetAccountDrawer, { - accounts: targetAccounts, - selectedAccount: account, - setToAccount: setToAccount, - setDrawerStateRef: setDrawerStateRef, - }); - }; - - const handleEditAccount = hideEdit ? undefined : showDrawer; - - if (!currency || (isDemo0Enabled && !hasRates)) return ; - - if (!account) - return ( - - ); - - return ; -}; - -export default React.memo(SectionTarget); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummaryLabel.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummaryLabel.tsx deleted file mode 100644 index 714f5b5e776f..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummaryLabel.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import Text from "~/renderer/components/Text"; -import Tooltip from "~/renderer/components/Tooltip"; -import IconInfoCircle from "~/renderer/icons/InfoCircle"; - -const Container = styled.div` - display: flex; - align-items: end; - column-gap: 0.25rem; - color: ${p => p.theme.colors.palette.text.shade40}; -`; -const Label = styled(Text).attrs(() => ({ - ff: "Inter", - fontSize: "13px", - fontWeight: 500, - lineHeight: "1.4", -}))` - &:first-letter { - text-transform: uppercase; - } -`; - -type DetailsProps = { - details?: string; -}; - -const Details = ({ details }: DetailsProps) => { - if (!details) return null; - return ( - - - - ); -}; - -/* This component fetch the current label and the optional details from the section's - ** context and render them if possible. - */ -const SummaryLabel = ({ label, details }: { label: string; details?: string }) => { - return ( - - - {details ?
: null} - - ); -}; - -export default SummaryLabel; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummarySection.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummarySection.tsx deleted file mode 100644 index 4da8687ed089..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummarySection.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React, { HTMLAttributes } from "react"; -import styled from "styled-components"; - -const Container = styled.div` - display: flex; - flex-direction: row; - justify-content: space-between; - min-height: 20px; -`; - -type SummarySectionProps = { - children: React.ReactNode; -} & HTMLAttributes; - -const SummarySection = ({ children, ...rest }: SummarySectionProps) => ( - {children} -); - -export default SummarySection; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummaryValue.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummaryValue.tsx deleted file mode 100644 index 773ff5cf0941..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/SummaryValue.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import styled from "styled-components"; -import ButtonBase from "~/renderer/components/Button"; -import TextBase from "~/renderer/components/Text"; - -export const Container = styled.div` - display: flex; - flex-direction: row; - column-gap: 0.375rem; - align-items: center; - color: ${p => p.theme.colors.palette.text.shade100}; - justify-content: flex-end; -`; -export const Text = styled(TextBase).attrs(() => ({ - ff: "Inter", - fontSize: "13px", - fontWeight: 600, - lineHeight: "1.4", -}))` - display: inline-block; - color: ${p => p.theme.colors.palette.secondary.main}; - - &:first-letter { - text-transform: uppercase; - } -`; -const Button = styled(ButtonBase).attrs(() => ({ - color: "palette.primary.main", -}))` - padding: 0; - height: unset; -`; - -export const NoValuePlaceholder = () => ( - - {"-"} - -); - -const SummaryValue = ({ - value, - handleChange, - children, -}: { - value?: string; - handleChange?: (() => void) | null; - children?: React.ReactNode; -}) => { - const { t } = useTranslation(); - - return ( - - {children} - {value && ( - - {value} - - )} - {handleChange ? ( - - ) : null} - - ); -}; - -export default SummaryValue; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/index.tsx deleted file mode 100644 index ebc31449d6bd..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/index.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { SwapTransactionType } from "@ledgerhq/live-common/exchange/swap/types"; -import React from "react"; -import styled from "styled-components"; -import { useIsSwapLiveFlagEnabled } from "../../hooks/useIsSwapLiveFlagEnabled"; -import SectionFees from "./SectionFees"; -import SectionTarget from "./SectionTarget"; - -// TODO fix the any types -const Form = styled.section.attrs<{ ready?: boolean }>(({ ready }) => ({ - style: ready - ? { - opacity: 1, - maxHeight: "100vh", - overflow: "auto", - } - : {}, -}))<{ ready?: boolean }>` - display: grid; - row-gap: 1.25rem; - color: white; - transition: - max-height 800ms cubic-bezier(0.47, 0, 0.75, 0.72), - opacity 400ms 400ms cubic-bezier(0.47, 0, 0.75, 0.72); - transform-origin: top; - height: auto; - opacity: 0; - max-height: 0; - overflow: hidden; -`; - -type SwapFormSummaryProps = { - swapTransaction: SwapTransactionType; - provider?: string; -}; - -const SwapFormSummary = ({ swapTransaction, provider }: SwapFormSummaryProps) => { - const { - transaction, - status, - updateTransaction, - setTransaction, - setToAccount, - swap: { targetAccounts }, - } = swapTransaction; - - const { - currency: fromCurrency, - account: fromAccount, - parentAccount: fromParentAccount, - } = swapTransaction.swap.from; - - const { currency: toCurrency, account: toAccount } = swapTransaction.swap.to; - const ratesState = swapTransaction.swap.rates; - const hasRates = ratesState?.value?.length && ratesState?.value?.length > 0; - const isDemo1Enabled = useIsSwapLiveFlagEnabled("ptxSwapLiveAppDemoOne"); - - return ( -
- - {!isDemo1Enabled && ( - - )} - - ); -}; -export default React.memo(SwapFormSummary); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/types.ts b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/types.ts deleted file mode 100644 index 1d8be912d667..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/types.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { SwapTransactionType } from "@ledgerhq/live-common/exchange/swap/types"; - -export type FormSummarySections = "provider" | "fees" | "rate" | "target"; -export type FormSummaryProps = { - provider?: string; - rate?: string; - fees?: string; - onProviderChange: Function; - onFeesChange: Function; - onTargetChange: Function; - swapTransaction: SwapTransactionType; -}; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Migrations/SwapMigrationUI.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Migrations/SwapMigrationUI.tsx deleted file mode 100644 index ad1cd2620491..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Migrations/SwapMigrationUI.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import styled from "styled-components"; - -import { usePageState } from "@ledgerhq/live-common/exchange/swap/hooks/index"; -import { SwapTransactionType } from "@ledgerhq/live-common/exchange/swap/types"; -import { Box } from "@ledgerhq/react-ui"; -import ButtonBase from "~/renderer/components/Button"; -import SwapFormRates from "../FormRates"; -import SwapFormSummary from "../FormSummary"; -import LoadingState from "../Rates/LoadingState"; -import { SwapWebManifestIDs } from "../SwapWebView"; -import { useIsSwapLiveFlagEnabled } from "../../hooks/useIsSwapLiveFlagEnabled"; - -const Button = styled(ButtonBase)` - width: 100%; - justify-content: center; -`; - -type SwapMigrationUIProps = { - liveAppEnabled: boolean; - liveApp: React.ReactNode; - manifestID: string | undefined; - // Demo 1 props - pageState: ReturnType; - swapTransaction: SwapTransactionType; - provider?: string; - // Demo 0 props - disabled: boolean; - onClick: () => void; -}; - -export const SwapMigrationUI = (props: SwapMigrationUIProps) => { - const { - liveAppEnabled, - liveApp, - manifestID, - pageState, - swapTransaction, - provider, - disabled, - onClick, - } = props; - const { t } = useTranslation(); - const isDemo1Enabled = useIsSwapLiveFlagEnabled("ptxSwapLiveAppDemoOne"); - - const nativeLoadingUI = pageState === "loading" ? : null; - const nativeNetworkFeesUI = - pageState === "loaded" || isDemo1Enabled ? ( - - ) : null; - - const nativeQuotesUI = - pageState === "loaded" && !isDemo1Enabled ? ( - - ) : null; - - const nativeExchangeButtonUI = ( - - - - ); - - /** - * Fall back to show all native UI. (without webview) - */ - const allNativeUI = ( - <> - {nativeLoadingUI} - {nativeNetworkFeesUI} - {nativeQuotesUI} - {nativeExchangeButtonUI} - - ); - - /** - * Live app disabled or unavailable, fallback to native UI - */ - if (!liveAppEnabled || !liveApp) { - return allNativeUI; - } - - switch (true) { - case manifestID?.startsWith(SwapWebManifestIDs.Demo0): - /** - * Demo 0 live app should only contain Exchange Button - * Rest should be in native UI (e.g quotes) - */ - return ( - <> - {nativeLoadingUI} - {nativeNetworkFeesUI} - {nativeQuotesUI} - {liveApp} - - ); - - case manifestID?.startsWith(SwapWebManifestIDs.Demo1): - case manifestID?.startsWith(SwapWebManifestIDs.Demo3): - /** - * Demo 1 live app should contain: - * - Exchange Button - * - Quotes UI - */ - return ( - <> - {nativeNetworkFeesUI} - {liveApp} - - ); - - /** - * Fall back to show all native UI - */ - default: - return allNativeUI; - } -}; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Countdown.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Countdown.tsx deleted file mode 100644 index 25742ce14284..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Countdown.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from "react"; -import { Trans } from "react-i18next"; -import styled from "styled-components"; -import Box from "~/renderer/components/Box"; -import Text from "~/renderer/components/Text"; -import AnimatedCountdown from "~/renderer/components/AnimatedCountdown"; -import { formatCountdown } from "~/renderer/screens/exchange/Swap2/Form/Rates/utils/formatCountdown"; -import { DEFAULT_SWAP_RATES_INTERVAL_MS } from "@ledgerhq/live-common/exchange/swap/const/timeout"; - -export type Props = { - countdown: number; -}; - -const CountdownText = styled(Text)` - color: ${p => p.theme.colors.neutral.c70}; -`; - -export default function Countdown({ countdown }: Props) { - return ( - <> - {countdown >= 0 ? ( - - - - - - - - - {formatCountdown(countdown)} - - - ) : ( - - - - )} - - ); -} diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/EmptyState.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/EmptyState.tsx deleted file mode 100644 index def65430840e..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/EmptyState.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import Box from "~/renderer/components/Box"; -import Text from "~/renderer/components/Text"; -import { Trans } from "react-i18next"; - -function EmptyState() { - return ( - - - - - - ); -} -export default React.memo(EmptyState); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/LoadingState.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/LoadingState.tsx deleted file mode 100644 index a4b857d07133..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/LoadingState.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import React, { useEffect, useState } from "react"; -import Box from "~/renderer/components/Box"; -import Text from "~/renderer/components/Text"; -import { useTranslation } from "react-i18next"; - -function Loader() { - const [dots, setDots] = useState(""); - useEffect(() => { - const interval = window.setInterval(() => { - setDots(dots => (dots.length < 3 ? dots + "." : "")); - }, 500); - return () => clearInterval(interval); - }, []); - - return ( - - {dots} - - ); -} - -function LoadingState() { - const { t } = useTranslation(); - - return ( - - - {t("swap2.form.rates.loadingQuotes")} - - - - {t("swap2.form.rates.loadingDescription")} - - - ); -} - -export default LoadingState; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/NoQuoteSwapRate.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/NoQuoteSwapRate.tsx deleted file mode 100644 index 2de60b16b09f..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/NoQuoteSwapRate.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React from "react"; -import { Text } from "@ledgerhq/react-ui"; -import styled from "styled-components"; -import { ExchangeRate } from "@ledgerhq/live-common/exchange/swap/types"; -import { Trans } from "react-i18next"; -import Rate from "./Rate"; -import { getProviderName } from "@ledgerhq/live-common/exchange/swap/utils/index"; - -export type Props = { - value: ExchangeRate; - onSelect: (a: ExchangeRate) => void; - selected?: boolean | null; - icon?: string; -}; - -const SecondaryText = styled(Text)` - color: ${p => p.theme.colors.neutral.c70}; -`; - -function NoQuoteSwapRate({ value, selected, onSelect, icon }: Props) { - return ( - } - rightContainer={ - - - - } - > - ); -} - -export default React.memo(NoQuoteSwapRate); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Rate.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Rate.tsx deleted file mode 100644 index 244cf65ddfc3..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Rate.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React, { useCallback } from "react"; -import styled from "styled-components"; -import { Text } from "@ledgerhq/react-ui"; -import Box from "~/renderer/components/Box"; -import ProviderIcon from "~/renderer/components/ProviderIcon"; -import { ExchangeRate } from "@ledgerhq/live-common/exchange/swap/types"; - -const ProviderContainer = styled(Box).attrs({ - horizontal: true, - alignItems: "center", - ff: "Inter|SemiBold", -})<{ selected?: boolean | null }>` - border: 1px solid ${p => p.theme.colors.palette.divider}; - border-radius: 4px; - cursor: pointer; - ${p => - p.selected - ? ` - border-color: ${p.theme.colors.palette.primary.main}; - box-shadow: 0px 0px 0px 4px ${p.theme.colors.primary.c60}; - background-color: ${p.theme.colors.primary.c20}; - ` - : ` - :hover { - box-shadow: 0px 0px 2px 1px ${p.theme.colors.palette.divider}; - }`} -`; -const SecondaryText = styled(Text)` - color: ${p => p.theme.colors.neutral.c70}; -`; - -export type Props = { - value: ExchangeRate; - onSelect: (a: ExchangeRate) => void; - selected?: boolean | null; - icon?: string; - title: string; - subtitle: React.ReactNode; - centerContainer?: JSX.Element; - rightContainer: JSX.Element; -}; - -function Rate({ - value, - selected, - onSelect, - icon, - title, - subtitle, - centerContainer, - rightContainer, -}: Props) { - const handleSelection = useCallback(() => onSelect(value), [value, onSelect]); - - return ( - - {icon && ( - - - - )} - - - - {title} - - {subtitle} - - - - {centerContainer} - - - {rightContainer} - - - - - ); -} - -export default React.memo(Rate); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/SwapRate.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/SwapRate.tsx deleted file mode 100644 index 4167b5052bd2..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/SwapRate.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import { Text } from "@ledgerhq/react-ui"; -import Box from "~/renderer/components/Box"; -import FormattedVal from "~/renderer/components/FormattedVal"; -import { ExchangeRate, SwapSelectorStateType } from "@ledgerhq/live-common/exchange/swap/types"; -import { getProviderName } from "@ledgerhq/live-common/exchange/swap/utils/index"; -import Price from "~/renderer/components/Price"; -import CounterValue from "~/renderer/components/CounterValue"; -import { Trans } from "react-i18next"; -import Rate from "./Rate"; -import { Currency } from "@ledgerhq/types-cryptoassets"; - -export type Props = { - value: ExchangeRate; - onSelect: (a: ExchangeRate) => void; - selected?: boolean | null; - fromCurrency?: SwapSelectorStateType["currency"]; - toCurrency?: SwapSelectorStateType["currency"]; - isRegistrationRequired: boolean; -}; - -const SecondaryText = styled(Text)` - color: ${p => p.theme.colors.neutral.c70}; -`; -const StyledCounterValue = styled(CounterValue)` - color: ${p => p.theme.colors.neutral.c70}; -`; - -function SwapRate({ - value, - selected, - onSelect, - fromCurrency, - toCurrency, - isRegistrationRequired, -}: Props) { - const { toAmount: amount, provider } = value; - return ( - - } - centerContainer={ - - - - - - - - - } - rightContainer={ - <> - - - - } - > - ); -} - -export default React.memo(SwapRate); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/filterRates.spec.ts b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/filterRates.spec.ts deleted file mode 100644 index 135b0e4dc521..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/filterRates.spec.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { ExchangeRate } from "@ledgerhq/live-common/exchange/swap/types"; -import { filterRates } from "~/renderer/screens/exchange/Swap2/Form/Rates/filterRates"; -import { FILTER } from "@ledgerhq/live-common/exchange/swap/utils/index"; - -const rates: Partial[] = [ - { - providerType: "CEX", - tradeMethod: "fixed", - provider: "changelly", - }, - { - providerType: "DEX", - tradeMethod: "fixed", - provider: "oneinch", - }, - { - providerType: "CEX", - tradeMethod: "float", - provider: "other-cex-provider", - }, - { - providerType: "DEX", - tradeMethod: "float", - provider: "other-dex-provider", - }, -]; - -describe("filterRates", () => { - it("does not apply any filters", () => { - const filtered = filterRates(rates as ExchangeRate[], []); - expect(filtered).toEqual(rates); - }); - - it("filters centralised rates", () => { - const filtered = filterRates(rates as ExchangeRate[], [FILTER.centralised]); - expect(filtered).toEqual([ - { - providerType: "CEX", - tradeMethod: "fixed", - provider: "changelly", - }, - { - providerType: "CEX", - tradeMethod: "float", - provider: "other-cex-provider", - }, - ]); - }); - - it("filters centralised floating rates", () => { - const filtered = filterRates(rates as ExchangeRate[], [FILTER.centralised, FILTER.float]); - expect(filtered).toEqual([ - { - providerType: "CEX", - tradeMethod: "float", - provider: "other-cex-provider", - }, - ]); - }); - - it("filters centralised fixed rates", () => { - const filtered = filterRates(rates as ExchangeRate[], [FILTER.centralised, FILTER.fixed]); - expect(filtered).toEqual([ - { - providerType: "CEX", - tradeMethod: "fixed", - provider: "changelly", - }, - ]); - }); - - it("filters decentralised rates", () => { - const filtered = filterRates(rates as ExchangeRate[], [FILTER.decentralised]); - expect(filtered).toEqual([ - { - providerType: "DEX", - tradeMethod: "fixed", - provider: "oneinch", - }, - { - providerType: "DEX", - tradeMethod: "float", - provider: "other-dex-provider", - }, - ]); - }); - - it("filters decentralised floating rates", () => { - const filtered = filterRates(rates as ExchangeRate[], [FILTER.decentralised, FILTER.float]); - expect(filtered).toEqual([ - { - providerType: "DEX", - tradeMethod: "float", - provider: "other-dex-provider", - }, - ]); - }); - - it("filters decentralised fixed rates", () => { - const filtered = filterRates(rates as ExchangeRate[], [FILTER.decentralised, FILTER.fixed]); - expect(filtered).toEqual([ - { - providerType: "DEX", - tradeMethod: "fixed", - provider: "oneinch", - }, - ]); - }); - - it("filters fixed rates", () => { - const filtered = filterRates(rates as ExchangeRate[], [FILTER.fixed]); - expect(filtered).toEqual([ - { - providerType: "CEX", - tradeMethod: "fixed", - provider: "changelly", - }, - { - providerType: "DEX", - tradeMethod: "fixed", - provider: "oneinch", - }, - ]); - }); - - it("filters floating rates", () => { - const filtered = filterRates(rates as ExchangeRate[], [FILTER.float]); - expect(filtered).toEqual([ - { - providerType: "CEX", - tradeMethod: "float", - provider: "other-cex-provider", - }, - { - providerType: "DEX", - tradeMethod: "float", - provider: "other-dex-provider", - }, - ]); - }); -}); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/filterRates.ts b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/filterRates.ts deleted file mode 100644 index 569a2f388052..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/filterRates.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ExchangeRate } from "@ledgerhq/live-common/exchange/swap/types"; -import { FILTER } from "@ledgerhq/live-common/exchange/swap/utils/index"; - -export const filterRates = ( - rates: ExchangeRate[] | undefined, - filters: string[], -): ExchangeRate[] => { - let filteredRates = rates ?? []; - for (const filter of filters) { - switch (filter) { - case FILTER.centralised: - filteredRates = filteredRates.filter(rate => rate.providerType === "CEX"); - break; - case FILTER.decentralised: - filteredRates = filteredRates.filter(rate => rate.providerType === "DEX"); - break; - case FILTER.float: - filteredRates = filteredRates.filter(rate => rate.tradeMethod === "float"); - break; - case FILTER.fixed: - filteredRates = filteredRates.filter(rate => rate.tradeMethod === "fixed"); - } - } - return filteredRates; -}; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/index.tsx deleted file mode 100644 index bd94f6ae9f22..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/index.tsx +++ /dev/null @@ -1,258 +0,0 @@ -import { getFeesUnit } from "@ledgerhq/live-common/account/index"; -import { formatCurrencyUnit } from "@ledgerhq/live-common/currencies/index"; -import { - ExchangeRate, - RatesReducerState, - SwapSelectorStateType, -} from "@ledgerhq/live-common/exchange/swap/types"; -import { isRegistrationRequired } from "@ledgerhq/live-common/exchange/swap/utils/index"; -import React, { useCallback, useEffect, useMemo, useState } from "react"; -import { Trans } from "react-i18next"; -import { useDispatch, useSelector } from "react-redux"; -import styled from "styled-components"; -import { rateSelector, updateRateAction } from "~/renderer/actions/swap"; -import { track } from "~/renderer/analytics/segment"; -import TrackPage from "~/renderer/analytics/TrackPage"; -import Box from "~/renderer/components/Box"; -import Text from "~/renderer/components/Text"; -import Tooltip from "~/renderer/components/Tooltip"; -import IconInfoCircle from "~/renderer/icons/InfoCircle"; -import { useGetSwapTrackingProperties } from "../../utils/index"; -import Countdown from "./Countdown"; -import { filterRates } from "./filterRates"; -import LoadingState from "./LoadingState"; -import NoQuoteSwapRate from "./NoQuoteSwapRate"; -import SwapRate from "./SwapRate"; - -type Props = { - fromCurrency: SwapSelectorStateType["currency"]; - toCurrency: SwapSelectorStateType["currency"]; - rates: RatesReducerState["value"]; - provider: string | undefined | null; - countdownSecondsToRefresh: number | undefined; -}; - -const TableHeader = styled(Box).attrs({ - horizontal: true, - alignItems: "center", - ff: "Inter|SemiBold", - justifyContent: "space-between", - fontWeight: "500", - fontSize: 3, - color: "palette.text.shade40", - pl: 3, - pr: 2, - mt: 3, - pb: 10, -})` - border-bottom: 1px solid ${p => p.theme.colors.neutral.c30}; -`; - -export default function ProviderRate({ - fromCurrency, - toCurrency, - rates, - provider, - countdownSecondsToRefresh, -}: Props) { - const swapDefaultTrack = useGetSwapTrackingProperties(); - const dispatch = useDispatch(); - const [filter] = useState([]); - const [defaultPartner, setDefaultPartner] = useState(null); - const [isRegistrationRequiredMap, setIsRegistrationRequiredMap] = useState<{ - [x: string]: boolean; - }>({}); - const selectedRate = useSelector(rateSelector); - const filteredRates = useMemo(() => filterRates(rates, filter), [rates, filter]); - const providers = useMemo(() => [...new Set(rates?.map(rate => rate.provider) ?? [])], [rates]); - const exchangeRates = useMemo(() => { - return toCurrency && rates - ? rates.map(({ toAmount }) => formatCurrencyUnit(getFeesUnit(toCurrency), toAmount)) - : []; - }, [toCurrency, rates]); - useEffect(() => { - if (providers) { - const fetchlol = async () => { - const results = await Promise.all( - providers.map(async provider => { - const isRequired = await isRegistrationRequired(provider); - return { [provider]: isRequired }; - }), - ); - - const resultsMap = results.reduce((acc, result) => ({ ...acc, ...result }), {}); - setIsRegistrationRequiredMap(resultsMap); - }; - fetchlol(); - } - }, [providers]); - const updateRate = useCallback( - (rate: ExchangeRate) => { - const value = rate.rate ?? rate.provider; - track("partner_clicked", { - page: "Page Swap Form", - ...swapDefaultTrack, - swap_type: rate.tradeMethod, - value, - partner: rate.provider, - defaultPartner, - }); - dispatch(updateRateAction(rate)); - }, - [defaultPartner, dispatch, swapDefaultTrack], - ); - - useEffect(() => { - // if the selected rate in redux is not in the filtered rates, we need to update it - if ( - selectedRate && - filteredRates.length > 0 && - !filteredRates.some( - r => r.provider === selectedRate.provider && r.tradeMethod === selectedRate.tradeMethod, - ) - ) { - const firstRate = filteredRates[0]; - setDefaultPartner(firstRate?.provider); - dispatch(updateRateAction(firstRate)); - } - - // if there is no selected rate but there is a filtered rate, we need to update it - if (!selectedRate && filteredRates.length > 0) { - const firstRate = filteredRates[0]; - setDefaultPartner(firstRate?.provider); - dispatch(updateRateAction(firstRate)); - } - - // if there are no filtered rates, we need to unset the selected rate - if (selectedRate && filteredRates.length === 0) { - setDefaultPartner(null); - dispatch(updateRateAction(null)); - } - }, [filteredRates, selectedRate, dispatch]); - - return ( - - - - - - - {countdownSecondsToRefresh && ( - - - - )} - - - - - - - - - - } - > - - - - - - - - - - - - - - - } - > - - - - - - - - - - - - - } - > - - - - - - - - {filteredRates.map(rate => { - const isSelected = - selectedRate && - selectedRate.provider === rate.provider && - selectedRate.tradeMethod === rate.tradeMethod; - return rate.providerType === "DEX" && rate.rate === undefined ? ( - - ) : ( - - ); - })} - - {!filteredRates.length && } - - ); -} diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/utils/formatCountdown.test.ts b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/utils/formatCountdown.test.ts deleted file mode 100644 index 2fc824bf9619..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/utils/formatCountdown.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { formatCountdown } from "~/renderer/screens/exchange/Swap2/Form/Rates/utils/formatCountdown"; - -describe("formatCountdown", () => { - it("formats countdown to timer", () => { - expect(formatCountdown(1)).toBe("00:01"); - expect(formatCountdown(10)).toBe("00:10"); - expect(formatCountdown(60)).toBe("01:00"); - expect(formatCountdown(61)).toBe("01:01"); - }); -}); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/utils/formatCountdown.ts b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/utils/formatCountdown.ts deleted file mode 100644 index b8981ce37f90..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/utils/formatCountdown.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const formatCountdown = (timeS: number) => { - const minutes = Math.floor(timeS / 60); - const seconds = timeS % 60; - return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`; -}; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/SwapWebView.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/SwapWebView.tsx deleted file mode 100644 index 44d35880b5bd..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/SwapWebView.tsx +++ /dev/null @@ -1,585 +0,0 @@ -import { - getAccountCurrency, - getMainAccount, - getParentAccount, -} from "@ledgerhq/live-common/account/helpers"; -import { handlers as loggerHandlers } from "@ledgerhq/live-common/wallet-api/CustomLogger/server"; -import { getAccountIdFromWalletAccountId } from "@ledgerhq/live-common/wallet-api/converters"; -import { SubAccount } from "@ledgerhq/types-live"; -import { SwapOperation } from "@ledgerhq/types-live/lib/swap"; -import BigNumber from "bignumber.js"; -import React, { useEffect, useMemo, useRef, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import styled from "styled-components"; -import { updateAccountWithUpdater } from "~/renderer/actions/accounts"; -import { Web3AppWebview } from "~/renderer/components/Web3AppWebview"; -import { initialWebviewState } from "~/renderer/components/Web3AppWebview/helpers"; -import { WebviewAPI, WebviewProps, WebviewState } from "~/renderer/components/Web3AppWebview/types"; -import { TopBar } from "~/renderer/components/WebPlatformPlayer/TopBar"; -import { context } from "~/renderer/drawers/Provider"; -import useTheme from "~/renderer/hooks/useTheme"; -import { - counterValueCurrencySelector, - discreetModeSelector, - enablePlatformDevToolsSelector, - languageSelector, -} from "~/renderer/reducers/settings"; -import { - transformToBigNumbers, - useGetSwapTrackingProperties, - useRedirectToSwapHistory, -} from "../utils/index"; -import WebviewErrorDrawer from "./WebviewErrorDrawer/index"; - -import { NetworkDown } from "@ledgerhq/errors"; -import { getAccountBridge } from "@ledgerhq/live-common/bridge/impl"; -import { formatCurrencyUnit } from "@ledgerhq/live-common/currencies/index"; -import { SwapExchangeRateAmountTooLow } from "@ledgerhq/live-common/errors"; -import { useSwapLiveConfig } from "@ledgerhq/live-common/exchange/swap/hooks/index"; -import { getAbandonSeedAddress } from "@ledgerhq/live-common/exchange/swap/hooks/useFromState"; -import { SwapLiveError } from "@ledgerhq/live-common/exchange/swap/types"; -import { - convertToAtomicUnit, - convertToNonAtomicUnit, - getCustomFeesPerFamily, -} from "@ledgerhq/live-common/exchange/swap/webApp/utils"; -import { LiveAppManifest } from "@ledgerhq/live-common/platform/types"; -import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets"; -import { useTranslation } from "react-i18next"; -import { track } from "~/renderer/analytics/segment"; -import { usePTXCustomHandlers } from "~/renderer/components/WebPTXPlayer/CustomHandlers"; -import { NetworkStatus, useNetworkStatus } from "~/renderer/hooks/useNetworkStatus"; -import { flattenAccountsSelector } from "~/renderer/reducers/accounts"; -import { captureException } from "~/sentry/renderer"; -import { CustomSwapQuotesState } from "../hooks/useSwapLiveAppQuoteState"; -import FeesDrawerLiveApp from "./FeesDrawerLiveApp"; - -export class UnableToLoadSwapLiveError extends Error { - constructor(message: string) { - const name = "UnableToLoadSwapLiveError"; - super(message || name); - this.name = name; - this.message = message; - } -} - -export type SwapProps = { - provider: string; - fromAccountId: string; - fromParentAccountId?: string; - toAccountId: string; - fromAmount: string; - toAmount?: string; - quoteId: string; - rate: string; - feeStrategy: string; - customFeeConfig: string; - cacheKey: string; - loading: boolean; - error: boolean; - providerRedirectURL: string; - toNewTokenId: string; - swapApiBase: string; - estimatedFees: string; - estimatedFeesUnit: string; -}; - -export type SwapWebProps = { - manifest: LiveAppManifest; - liveAppUnavailable: () => void; - setQuoteState?: (next: CustomSwapQuotesState) => void; - swapState?: Partial; - isMaxEnabled?: boolean; - sourceCurrency?: TokenCurrency | CryptoCurrency; - targetCurrency?: TokenCurrency | CryptoCurrency; -}; - -export const SwapWebManifestIDs = { - Demo0: "swap-live-app-demo-0", - Demo1: "swap-live-app-demo-1", - Demo3: "swap-live-app-demo-3", -}; - -const SwapWebAppWrapper = styled.div` - width: 100%; - flex: 1; -`; - -const getSegWitAbandonSeedAddress = (): string => "bc1qed3mqr92zvq2s782aqkyx785u23723w02qfrgs"; - -const defaultContentSize: Record = {}; - -const SwapWebView = ({ - manifest, - swapState, - liveAppUnavailable, - isMaxEnabled, - sourceCurrency, - targetCurrency, - setQuoteState, -}: SwapWebProps) => { - const { - colors: { - palette: { type: themeType }, - }, - } = useTheme(); - const dispatch = useDispatch(); - const { t } = useTranslation(); - const webviewAPIRef = useRef(null); - const { setDrawer } = React.useContext(context); - const accounts = useSelector(flattenAccountsSelector); - const [webviewState, setWebviewState] = useState(initialWebviewState); - const discreetMode = useSelector(discreetModeSelector); - const fiatCurrency = useSelector(counterValueCurrencySelector); - const locale = useSelector(languageSelector); - const redirectToHistory = useRedirectToSwapHistory(); - const enablePlatformDevTools = useSelector(enablePlatformDevToolsSelector); - const { networkStatus } = useNetworkStatus(); - const isOffline = networkStatus === NetworkStatus.OFFLINE; - const swapDefaultTrack = useGetSwapTrackingProperties(); - const swapLiveEnabledFlag = useSwapLiveConfig(); - - const hasSwapState = !!swapState; - const customPTXHandlers = usePTXCustomHandlers(manifest, accounts); - - const { fromCurrency, addressFrom, addressTo } = useMemo(() => { - const [, , fromCurrency, addressFrom] = - getAccountIdFromWalletAccountId(swapState?.fromAccountId || "")?.split(":") || []; - - const [, , toCurrency, addressTo] = - getAccountIdFromWalletAccountId(swapState?.toAccountId || "")?.split(":") || []; - - return { - fromCurrency, - addressFrom, - toCurrency, - addressTo, - }; - }, [swapState?.fromAccountId, swapState?.toAccountId]); - - const [windowContentSize, setWindowContentSize] = useState(defaultContentSize); - - const customHandlers = useMemo(() => { - return { - ...loggerHandlers, - ...customPTXHandlers, - "custom.swapStateGet": () => { - return Promise.resolve(swapState); - }, - "custom.setContentSize": ({ params }: { params?: Record }) => { - if (params) { - setWindowContentSize(params); - } - return Promise.resolve(); - }, - "custom.setQuote": (quote: { - params?: { - amountTo?: number; - amountToCounterValue?: { value: number; fiat: string }; - code?: string; - parameter: { minAmount: string; maxAmount: string }; - }; - }) => { - const toUnit = targetCurrency?.units[0]; - const fromUnit = sourceCurrency?.units[0]; - - if (!quote.params) { - setQuoteState?.({ - amountTo: undefined, - swapError: undefined, - counterValue: undefined, - }); - return Promise.resolve(); - } - - if (quote.params?.code && fromUnit) { - switch (quote.params.code) { - case "minAmountError": - setQuoteState?.({ - amountTo: undefined, - counterValue: undefined, - swapError: new SwapExchangeRateAmountTooLow(undefined, { - minAmountFromFormatted: formatCurrencyUnit( - fromUnit, - new BigNumber(quote.params.parameter.minAmount).times(10 ** fromUnit.magnitude), - { - alwaysShowSign: false, - disableRounding: true, - showCode: true, - }, - ), - }), - }); - return Promise.resolve(); - case "maxAmountError": - setQuoteState?.({ - amountTo: undefined, - counterValue: undefined, - swapError: new SwapExchangeRateAmountTooLow(undefined, { - minAmountFromFormatted: formatCurrencyUnit( - fromUnit, - new BigNumber(quote.params.parameter.maxAmount).times(10 ** fromUnit.magnitude), - { - alwaysShowSign: false, - disableRounding: true, - showCode: true, - }, - ), - }), - }); - return Promise.resolve(); - } - } - - if (toUnit && quote?.params?.amountTo) { - const amountTo = BigNumber(quote?.params?.amountTo).times(10 ** toUnit.magnitude); - const counterValue = quote?.params?.amountToCounterValue?.value - ? BigNumber(quote.params.amountToCounterValue.value).times( - 10 ** fiatCurrency.units[0].magnitude, - ) - : undefined; - - setQuoteState?.({ - amountTo, - counterValue: counterValue, - swapError: undefined, - }); - } - - return Promise.resolve(); - }, - // TODO: when we need bidirectional communication - // "custom.swapStateSet": (params: CustomHandlersParams) => { - // return Promise.resolve(); - // }, - "custom.saveSwapToHistory": ({ - params, - }: { - params: { swap: SwapProps; transaction_id: string }; - }) => { - const { swap, transaction_id } = params; - if (!swap || !transaction_id || !swap.provider || !swap.fromAmount || !swap.toAmount) { - return Promise.reject("Cannot save swap missing params"); - } - const fromId = getAccountIdFromWalletAccountId(swap.fromAccountId); - const toId = getAccountIdFromWalletAccountId(swap.toAccountId); - if (!fromId || !toId) return Promise.reject("Accounts not found"); - const operationId = `${fromId}-${transaction_id}-OUT`; - - const swapOperation: SwapOperation = { - status: "pending", - provider: swap.provider, - operationId, - swapId: transaction_id, - receiverAccountId: toId, - tokenId: toId, - fromAmount: new BigNumber(swap.fromAmount), - toAmount: new BigNumber(swap.toAmount), - }; - - dispatch( - updateAccountWithUpdater(fromId, account => { - const fromCurrency = getAccountCurrency(account); - const isFromToken = fromCurrency.type === "TokenCurrency"; - const subAccounts = account.type === "Account" && account.subAccounts; - return isFromToken && subAccounts - ? { - ...account, - subAccounts: subAccounts.map((a: SubAccount) => { - const subAccount = { - ...a, - swapHistory: [...a.swapHistory, swapOperation], - }; - return a.id === fromId ? subAccount : a; - }), - } - : { ...account, swapHistory: [...account.swapHistory, swapOperation] }; - }), - ); - return Promise.resolve(); - }, - "custom.swapRedirectToHistory": () => { - redirectToHistory(); - }, - "custom.getFee": async ({ - params, - }: { - params: { - fromAccountId: string; - fromAmount: string; - feeStrategy: string; - openDrawer: boolean; - customFeeConfig: object; - SWAP_VERSION: string; - }; - }): Promise<{ - feesStrategy: string; - estimatedFees: BigNumber | undefined; - errors: object; - warnings: object; - customFeeConfig: object; - }> => { - const realFromAccountId = getAccountIdFromWalletAccountId(params.fromAccountId); - if (!realFromAccountId) { - return Promise.reject(new Error(`accountId ${params.fromAccountId} unknown`)); - } - - const fromAccount = accounts.find(acc => acc.id === realFromAccountId); - if (!fromAccount) { - return Promise.reject(new Error(`accountId ${params.fromAccountId} unknown`)); - } - const fromParentAccount = getParentAccount(fromAccount, accounts); - - const mainAccount = getMainAccount(fromAccount, fromParentAccount); - const bridge = getAccountBridge(fromAccount, fromParentAccount); - - const subAccountId = fromAccount.type !== "Account" && fromAccount.id; - const transaction = bridge.createTransaction(mainAccount); - - const preparedTransaction = await bridge.prepareTransaction(mainAccount, { - ...transaction, - subAccountId, - recipient: - mainAccount.currency.id === "bitcoin" - ? getSegWitAbandonSeedAddress() - : getAbandonSeedAddress(mainAccount.currency.id), - amount: convertToAtomicUnit({ - amount: new BigNumber(params.fromAmount), - account: fromAccount, - }), - feesStrategy: params.feeStrategy || "medium", - ...transformToBigNumbers(params.customFeeConfig), - }); - let status = await bridge.getTransactionStatus(mainAccount, preparedTransaction); - const statusInit = status; - let finalTx = preparedTransaction; - let customFeeConfig = transaction && getCustomFeesPerFamily(finalTx); - const setTransaction = async (newTransaction: Transaction): Promise => { - status = await bridge.getTransactionStatus(mainAccount, newTransaction); - customFeeConfig = transaction && getCustomFeesPerFamily(newTransaction); - finalTx = newTransaction; - return newTransaction; - }; - - if (!params.openDrawer) { - // filters out the custom fee config for chains without drawer - const config = ["evm", "bitcoin"].includes(transaction.family) - ? { hasDrawer: true, ...customFeeConfig } - : {}; - return { - feesStrategy: finalTx.feesStrategy, - estimatedFees: convertToNonAtomicUnit({ - amount: status.estimatedFees, - account: mainAccount, - }), - errors: status.errors, - warnings: status.warnings, - customFeeConfig: config, - }; - } - - return new Promise<{ - feesStrategy: string; - estimatedFees: BigNumber | undefined; - errors: object; - warnings: object; - customFeeConfig: object; - }>(resolve => { - const performClose = (save: boolean) => { - track("button_clicked2", { - button: save ? "continueNetworkFees" : "closeNetworkFees", - page: "quoteSwap", - ...swapDefaultTrack, - swapVersion: params.SWAP_VERSION, - value: finalTx.feesStrategy || "custom", - }); - setDrawer(undefined); - if (!save) { - resolve({ - feesStrategy: params.feeStrategy, - estimatedFees: convertToNonAtomicUnit({ - amount: statusInit.estimatedFees, - account: mainAccount, - }), - errors: statusInit.errors, - warnings: statusInit.warnings, - customFeeConfig, - }); - } - resolve({ - // little hack to make sure we do not return null (for bitcoin for instance) - feesStrategy: finalTx.feesStrategy || "custom", - estimatedFees: convertToNonAtomicUnit({ - amount: status.estimatedFees, - account: mainAccount, - }), - errors: status.errors, - warnings: status.warnings, - customFeeConfig, - }); - }; - - setDrawer( - FeesDrawerLiveApp, - { - setTransaction, - account: fromAccount, - parentAccount: fromParentAccount, - status: status, - provider: undefined, - disableSlowStrategy: true, - transaction: preparedTransaction, - onRequestClose: (save: boolean) => performClose(save), - }, - { - title: t("swap2.form.details.label.fees"), - forceDisableFocusTrap: true, - onRequestClose: () => performClose(false), - }, - ); - }); - }, - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [swapState]); - - useEffect(() => { - if (webviewState.url.includes("/unknown-error")) { - // the live app has re-directed to /unknown-error. Handle this in callback, probably wallet-api failure. - onSwapWebviewError(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [webviewState.url]); - - const hashString = useMemo(() => { - const searchParams = new URLSearchParams(); - - const swapParams = { - addressFrom: addressFrom, - addressTo: addressTo, - amountFrom: swapState?.fromAmount, - from: sourceCurrency?.id, - hasError: swapState?.error ? "true" : undefined, // append param only if error is true - isMaxEnabled: isMaxEnabled, - loading: swapState?.loading, - fromParentAccountId: swapState?.fromParentAccountId, - swapApiBase: process.env.SWAP_API_BASE, - networkFees: swapState?.estimatedFees, - networkFeesCurrency: fromCurrency, - provider: swapState?.provider, - to: targetCurrency?.id, - toAccountId: swapState?.toAccountId, - fromAccountId: swapState?.fromAccountId, - toNewTokenId: swapState?.toNewTokenId, - feeStrategy: swapState?.feeStrategy, - customFeeConfig: swapState?.customFeeConfig, - ...(swapLiveEnabledFlag?.params && - "variant" in swapLiveEnabledFlag.params && - swapLiveEnabledFlag.params.variant === "Demo0" - ? { ptxSwapCoreExperiment: "Demo0" } - : {}), - }; - - Object.entries(swapParams).forEach(([key, value]) => { - if (value != null) { - // Convert all values to string as URLSearchParams expects string values - searchParams.append(key, String(value)); - } - }); - - return searchParams.toString(); - }, [ - addressFrom, - addressTo, - swapState?.fromAmount, - swapState?.error, - swapState?.loading, - swapState?.fromParentAccountId, - swapState?.estimatedFees, - swapState?.provider, - swapState?.toAccountId, - swapState?.fromAccountId, - swapState?.toNewTokenId, - swapState?.feeStrategy, - swapState?.customFeeConfig, - sourceCurrency?.id, - isMaxEnabled, - fromCurrency, - targetCurrency?.id, - swapLiveEnabledFlag?.params, - ]); - - useEffect(() => { - // Determine the new quote state based on network status - setQuoteState?.({ - amountTo: undefined, - counterValue: undefined, - ...{ - swapError: isOffline ? new NetworkDown() : undefined, - }, - }); - - // This effect runs when the network status changes or the target account changes - // when the toAccountId has changed, quote state should be reset - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [networkStatus, swapState?.toAccountId]); - - const webviewStyle = useMemo( - () => ({ minHeight: windowContentSize.scrollHeight }), - [windowContentSize.scrollHeight], - ); - - // return loader??? - if (!hasSwapState || isOffline) { - return null; - } - - const onSwapWebviewError = (error?: SwapLiveError) => { - console.error("onSwapWebviewError", error); - setDrawer(WebviewErrorDrawer, error); - }; - - const onStateChange: WebviewProps["onStateChange"] = state => { - setWebviewState(state); - - if (!state.loading && state.isAppUnavailable) { - liveAppUnavailable(); - captureException( - new UnableToLoadSwapLiveError( - '"Failed to load swap live app using WebPlatformPlayer in SwapWeb",', - ), - ); - } - }; - - return ( - <> - {enablePlatformDevTools && ( - - )} - - - - - - ); -}; - -export default SwapWebView; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/SwapWebViewDemo3.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/SwapWebViewDemo3.tsx index a4ecf0c9a84f..59d09c3a3854 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/SwapWebViewDemo3.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/SwapWebViewDemo3.tsx @@ -7,7 +7,6 @@ import { getEnv } from "@ledgerhq/live-env"; import { getNodeApi } from "@ledgerhq/coin-evm/api/node/index"; import { getMainAccount, getParentAccount } from "@ledgerhq/live-common/account/helpers"; import { getAccountBridge } from "@ledgerhq/live-common/bridge/impl"; -import { useSwapLiveConfig } from "@ledgerhq/live-common/exchange/swap/hooks/live-app-migration/useSwapLiveConfig"; import { getAbandonSeedAddress } from "@ledgerhq/live-common/exchange/swap/hooks/useFromState"; import { convertToAtomicUnit, @@ -53,6 +52,7 @@ import { } from "../utils/index"; import FeesDrawerLiveApp from "./FeesDrawerLiveApp"; import WebviewErrorDrawer from "./WebviewErrorDrawer/index"; + export class UnableToLoadSwapLiveError extends Error { constructor(message: string) { const name = "UnableToLoadSwapLiveError"; @@ -128,8 +128,6 @@ const SwapWebView = ({ manifest, liveAppUnavailable }: SwapWebProps) => { defaultParentAccount?: Account; from?: string; }>(); - const swapLiveEnabledFlag = useSwapLiveConfig(); - const { networkStatus } = useNetworkStatus(); const isOffline = networkStatus === NetworkStatus.OFFLINE; @@ -406,20 +404,8 @@ const SwapWebView = ({ manifest, liveAppUnavailable }: SwapWebProps) => { } : {}), ...(state?.from ? { fromPath: simplifyFromPath(state?.from) } : {}), - ...(swapLiveEnabledFlag?.params && "variant" in swapLiveEnabledFlag.params - ? { - ptxSwapCoreExperiment: swapLiveEnabledFlag.params?.variant as string, - } - : {}), }).toString(), - [ - isOffline, - state?.defaultAccount, - state?.defaultParentAccount, - state?.from, - walletState, - swapLiveEnabledFlag, - ], + [isOffline, state?.defaultAccount, state?.defaultParentAccount, state?.from, walletState], ); const onSwapWebviewError = (error?: SwapLiveError) => { diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/TargetAccountDrawer/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/TargetAccountDrawer/index.tsx deleted file mode 100644 index 3201edc1d968..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/TargetAccountDrawer/index.tsx +++ /dev/null @@ -1,286 +0,0 @@ -import React, { memo, useState, useEffect, useCallback, useMemo } from "react"; -import styled, { useTheme } from "styled-components"; -import { Trans } from "react-i18next"; -import { DrawerTitle } from "../DrawerTitle"; -import Box from "~/renderer/components/Box"; -import Text from "~/renderer/components/Text"; -import FormattedVal from "~/renderer/components/FormattedVal"; -import CryptoCurrencyIcon from "~/renderer/components/CryptoCurrencyIcon"; -import { AccountLike } from "@ledgerhq/types-live"; -import { getAccountCurrency } from "@ledgerhq/live-common/account/index"; -import Check from "~/renderer/icons/Check"; -import { SwapTransactionType } from "@ledgerhq/live-common/exchange/swap/types"; -import Tabbable from "~/renderer/components/Box/Tabbable"; -import { useDispatch, useSelector } from "react-redux"; -import { openModal } from "~/renderer/actions/modals"; -import Plus from "~/renderer/icons/Plus"; -import { rgba } from "~/renderer/styles/helpers"; -import { shallowAccountsSelector } from "~/renderer/reducers/accounts"; -import { context } from "~/renderer/drawers/Provider"; -import { track } from "~/renderer/analytics/segment"; -import { useGetSwapTrackingProperties } from "../../utils/index"; -import { useAccountUnit } from "~/renderer/hooks/useAccountUnit"; -import { getDefaultAccountName } from "@ledgerhq/live-wallet/accountName"; -import { useAccountName, useMaybeAccountName } from "~/renderer/reducers/wallet"; - -const NonSelectableAccountWrapper = styled(Box)` - column-gap: 8px; -`; - -const AccountWrapper = styled(Tabbable)<{ selected?: boolean }>` - cursor: pointer; - column-gap: 8px; - &:hover { - background-color: ${p => p.theme.colors.palette.text.shade10}; - } - ${p => - p.selected - ? ` - background-color: ${p.theme.colors.palette.background.default}; - ` - : ""}; -`; -const AddAccountIconContainer = styled(Tabbable)` - padding: 5px; - border-radius: 9999px; - color: ${p => p.theme.colors.palette.primary.main}; - background: ${p => rgba(p.theme.colors.palette.primary.main, 0.2)}; -`; - -const AccountBox = styled(Box)` - &, - ${Text} { - flex-shrink: 1; - } - - ${Text} { - overflow: hidden; - text-overflow: ellipsis; - } -`; - -function AddAccountIcon() { - return ( - - - - ); -} - -const TargetAccount = memo(function TargetAccount({ - account, - selected, - setAccount, - isChild, -}: { - account: AccountLike; - selected?: boolean; - setAccount?: Props["setToAccount"]; - isChild?: boolean; -}) { - const swapDefaultTrack = useGetSwapTrackingProperties(); - const allAccounts = useSelector(shallowAccountsSelector); - const theme = useTheme(); - const currency = getAccountCurrency(account); - const unit = useAccountUnit(account); - const name = useAccountName(account); - const parentAccount = - account?.type !== "Account" ? allAccounts?.find(a => a.id === account?.parentId) : undefined; - const parentName = useMaybeAccountName(parentAccount); - const balance = account.spendableBalance || account.balance; - - const onClick = useCallback(() => { - track("button_clicked2", { - page: "Swap accounts", - ...swapDefaultTrack, - button: "account", - currency, - account: name, - parentAccount: parentName, - }); - setAccount && setAccount(currency, account, parentAccount || undefined); - }, [swapDefaultTrack, currency, name, parentName, setAccount, account, parentAccount]); - - const Wrapper: React.ComponentType< - React.ComponentProps & React.ComponentProps - > = setAccount ? AccountWrapper : NonSelectableAccountWrapper; - - return ( - - - {isChild && ( - - )} - - - - - {name} - - - - - {selected && ( - - - - )} - - - ); -}); -type Props = { - accounts: AccountLike[] | undefined; - selectedAccount: AccountLike | undefined; - setToAccount: SwapTransactionType["setToAccount"]; - setDrawerStateRef: { - current: - | ((a: { selectedAccount: AccountLike; targetAccounts: AccountLike[] }) => void) - | undefined - | null; - }; -}; - -export default function TargetAccountDrawer({ - accounts, - selectedAccount: initialSelectedAccount, - setToAccount, - setDrawerStateRef, -}: Props) { - const swapDefaultTrack = useGetSwapTrackingProperties(); - const allAccounts = useSelector(shallowAccountsSelector); - const dispatch = useDispatch(); - const { setDrawer } = React.useContext(context); - const [{ selectedAccount, targetAccounts }, setState] = useState({ - selectedAccount: initialSelectedAccount, - targetAccounts: accounts, - }); - const currency = getAccountCurrency(selectedAccount); - useEffect(() => { - setDrawerStateRef.current = setState; - return () => { - setDrawerStateRef.current = null; - }; - }, [setDrawerStateRef]); - const handleAddAccount = () => - dispatch( - openModal("MODAL_ADD_ACCOUNTS", { - currency, - ...swapDefaultTrack, - }), - ); - const handleAccountPick: Props["setToAccount"] = (currency, account, parentAccount) => { - setToAccount(currency, account, parentAccount); - setDrawer(undefined); - }; - - const accountsList: - | { - account: AccountLike; - subAccounts: AccountLike[]; - }[] - | undefined = useMemo( - () => - targetAccounts && - Object.values( - targetAccounts.reduce( - (result, account) => { - const parentId = "parentId" in account && account.parentId; - if (parentId) { - result[parentId] = result[parentId] ?? { - account: allAccounts.find(acc => acc.id === parentId), - subAccounts: [], - }; - result[parentId].subAccounts.push(account); - return result; - } else { - result[account.id] = result[account.id] ?? { - account, - subAccounts: [], - }; - return result; - } - }, - {} as Record< - string, - { - account: AccountLike; - subAccounts: AccountLike[]; - } - >, - ), - ), - [targetAccounts, allAccounts], - ); - - return ( - - - - {accountsList?.map(({ account, subAccounts }) => ( - <> - - {subAccounts.map(account => ( - - ))} - - ))} - - - - - - - - - - - ); -} diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx deleted file mode 100644 index 60673be70446..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx +++ /dev/null @@ -1,527 +0,0 @@ -import { NotEnoughBalance, NotEnoughBalanceSwap } from "@ledgerhq/errors"; -import { getParentAccount, isTokenAccount } from "@ledgerhq/live-common/account/index"; -import { - SetExchangeRateCallback, - useIsSwapLiveApp, - usePageState, - useSwapLiveConfig, - useSwapTransaction, -} from "@ledgerhq/live-common/exchange/swap/hooks/index"; -import { - maybeKeepTronAccountAlive, - maybeTezosAccountUnrevealedAccount, - maybeTronEmptyAccount, -} from "@ledgerhq/live-common/exchange/swap/index"; -import { OnNoRatesCallback } from "@ledgerhq/live-common/exchange/swap/types"; -import { getProviderName } from "@ledgerhq/live-common/exchange/swap/utils/index"; -import { - convertToNonAtomicUnit, - getCustomFeesPerFamily, -} from "@ledgerhq/live-common/exchange/swap/webApp/index"; -import useFeature from "@ledgerhq/live-common/featureFlags/useFeature"; -import { useRemoteLiveAppManifest } from "@ledgerhq/live-common/platform/providers/RemoteLiveAppProvider/index"; -import { useLocalLiveAppManifest } from "@ledgerhq/live-common/wallet-api/LocalLiveAppProvider/index"; -import { accountToWalletAPIAccount } from "@ledgerhq/live-common/wallet-api/converters"; -import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets"; -import { AccountLike } from "@ledgerhq/types-live"; -import BigNumber from "bignumber.js"; -import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { useHistory, useLocation } from "react-router-dom"; -import styled from "styled-components"; -import { rateSelector, updateRateAction, updateTransactionAction } from "~/renderer/actions/swap"; -import TrackPage from "~/renderer/analytics/TrackPage"; -import { track } from "~/renderer/analytics/segment"; -import { context } from "~/renderer/drawers/Provider"; -import { useSwapLiveAppHook } from "~/renderer/hooks/swap-migrations/useSwapLiveAppHook"; -import { flattenAccountsSelector, shallowAccountsSelector } from "~/renderer/reducers/accounts"; -import { languageSelector } from "~/renderer/reducers/settings"; -import { walletSelector } from "~/renderer/reducers/wallet"; -import { useIsSwapLiveFlagEnabled } from "../hooks/useIsSwapLiveFlagEnabled"; -import { useSwapLiveAppQuoteState } from "../hooks/useSwapLiveAppQuoteState"; -import { trackSwapError, useGetSwapTrackingProperties } from "../utils/index"; -import ExchangeDrawer from "./ExchangeDrawer/index"; -import SwapFormSelectors from "./FormSelectors"; -import { SwapMigrationUI } from "./Migrations/SwapMigrationUI"; -import EmptyState from "./Rates/EmptyState"; -import SwapWebView, { SwapWebProps } from "./SwapWebView"; - -const DAPP_PROVIDERS = ["paraswap", "oneinch", "moonpay"]; - -const Wrapper = styled.div` - display: flex; - flex-direction: column; - max-width: 37rem; - padding: 0.75rem ${({ theme }) => theme.space[4]}px 0; - row-gap: 1rem; - @media screen and (min-height: 1200px) { - padding-top: 1rem; - row-gap: 1.5rem; - } -`; - -const idleTime = 60 * 60000; // 1 hour - -const SwapForm = () => { - const language = useSelector(languageSelector); - const [idleState, setIdleState] = useState(false); - const dispatch = useDispatch(); - const { state: locationState } = useLocation(); - const history = useHistory(); - const totalListedAccounts = useSelector(flattenAccountsSelector); - const accounts = useSelector(shallowAccountsSelector); - const exchangeRate = useSelector(rateSelector); - const walletApiPartnerList = useFeature("swapWalletApiPartnerList"); - const ptxSwapReceiveTRC20WithoutTrx = useFeature("ptxSwapReceiveTRC20WithoutTrx"); - const swapDefaultTrack = useGetSwapTrackingProperties(); - - const setExchangeRate: SetExchangeRateCallback = useCallback( - rate => { - dispatch(updateRateAction(rate)); - }, - [dispatch], - ); - - const onNoRates: OnNoRatesCallback = useCallback( - ({ toState }) => { - track("error_message", { - message: "no_rates", - page: "Page Swap Form", - ...swapDefaultTrack, - sourceCurrency: toState.currency?.name, - }); - }, - [swapDefaultTrack], - ); - - const swapLiveEnabledFlag = useSwapLiveConfig(); - const swapLiveAppManifestID = swapLiveEnabledFlag?.params?.manifest_id; - const isDemo1Enabled = useIsSwapLiveFlagEnabled("ptxSwapLiveAppDemoOne"); - - const swapTransaction = useSwapTransaction({ - accounts, - setExchangeRate, - onNoRates, - isEnabled: !isDemo1Enabled, - ...(locationState as object), - }); - - const isSwapLiveAppEnabled = useIsSwapLiveApp({ - currencyFrom: swapTransaction.swap.from.currency, - }); - - // @TODO: Try to check if we can directly have the right state from `useSwapTransaction` - // Used to set the fake transaction recipient - // As of today, we need to call setFromAccount to trigger an updateTransaction - // in order to set the correct recipient address (abandonSeed address) - // cf. https://github.com/LedgerHQ/ledger-live/blob/c135c887b313ecc9f4a3b3a421ced0e3a081dc37/libs/ledger-live-common/src/exchange/swap/hooks/useFromState.ts#L50-L57 - useEffect(() => { - if (swapTransaction.account) { - swapTransaction.setFromAccount(swapTransaction.account); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const exchangeRatesState = swapTransaction.swap?.rates; - const keepTronAccountAliveError = maybeKeepTronAccountAlive(swapTransaction); - const swapError = keepTronAccountAliveError - ? keepTronAccountAliveError - : swapTransaction.fromAmountError instanceof NotEnoughBalance - ? new NotEnoughBalanceSwap(swapTransaction.fromAmountError?.message) - : swapTransaction.fromAmountError || - exchangeRatesState?.error || - maybeTezosAccountUnrevealedAccount(swapTransaction) || - (ptxSwapReceiveTRC20WithoutTrx?.enabled - ? undefined - : maybeTronEmptyAccount(swapTransaction)); - - const swapWarning = swapTransaction.fromAmountWarning; - const pageState = usePageState(swapTransaction, swapError); - const provider = useMemo(() => exchangeRate?.provider, [exchangeRate?.provider]); - const idleTimeout = useRef(); - const [swapWebProps, setSwapWebProps] = useState( - undefined, - ); - const { setDrawer } = React.useContext(context); - const walletState = useSelector(walletSelector); - - const getExchangeSDKParams = useCallback(() => { - const { swap, transaction } = swapTransaction; - const { to, from } = swap; - const { account: fromAccount, parentAccount: fromParentAccount } = from; - const { account: toAccount, parentAccount: toParentAccount } = to; - const { feesStrategy } = transaction || {}; - const { rate, rateId } = exchangeRate || {}; - - const isToAccountValid = totalListedAccounts.some(account => account.id === toAccount?.id); - const fromAccountId = - fromAccount && accountToWalletAPIAccount(walletState, fromAccount, fromParentAccount)?.id; - const toAccountId = isToAccountValid - ? toAccount && accountToWalletAPIAccount(walletState, toAccount, toParentAccount)?.id - : toParentAccount && accountToWalletAPIAccount(walletState, toParentAccount, undefined)?.id; - const toNewTokenId = - !isToAccountValid && toAccount?.type === "TokenAccount" ? toAccount.token?.id : undefined; - const fromAmount = - fromAccount && - convertToNonAtomicUnit({ - amount: transaction?.amount, - account: fromAccount, - }); - - const customFeeConfig = transaction && getCustomFeesPerFamily(transaction); - // The Swap web app will automatically recreate the transaction with "default" fees. - // However, if you wish to use a different fee type, you will need to set it as custom. - const feeStrategyParam = - feesStrategy && ["slow", "fast", "custom"].includes(feesStrategy) ? "CUSTOM" : "MEDIUM"; - - return { - fromAccountId, - toAccountId, - fromAmount: fromAmount?.toString(), - quoteId: rateId ? rateId : undefined, - rate: rate?.toString(), - feeStrategy: feeStrategyParam, - customFeeConfig: customFeeConfig ? JSON.stringify(customFeeConfig) : undefined, - toNewTokenId, - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - provider, - swapTransaction.swap.from.account?.id, - swapTransaction.swap.to.currency?.id, - swapTransaction.swap.to.account?.id, - swapTransaction.swap.from.amount, - exchangeRate?.providerType, - exchangeRate?.tradeMethod, - exchangeRate?.providerURL, - exchangeRate, - totalListedAccounts, - ]); - - const generateMoonpayUrl = useCallback( - ({ base = "", args = {} }: { base: string; args: { [key: string]: string | undefined } }) => { - const moonpayURL = new URL(base || ""); - moonpayURL.searchParams.append("ledgerlive", `${true}`); - Object.entries(args).forEach( - ([key, value]) => - // customFeeConfig is an object - value && - moonpayURL.searchParams.append( - ...[key, typeof value === "object" ? JSON.stringify(value) : value], - ), - ); - moonpayURL.searchParams.set("language", language); - - // Theme ID is defined by moonpay to tweak styling to more more closely match - // the existing theming within ledger live. - moonpayURL.searchParams.set("themeId", "92be4cb6-a57f-407b-8b1f-bc8055b60c9b"); - return moonpayURL; - }, - [language], - ); - - const getProviderRedirectURLSearch = useCallback(() => { - const { account: fromAccount, parentAccount: fromParentAccount } = swapTransaction.swap.from; - const providerRedirectFromAccountId = - fromAccount && - provider && - walletApiPartnerList?.enabled && - walletApiPartnerList?.params?.list.includes(provider) - ? accountToWalletAPIAccount(walletState, fromAccount, fromParentAccount)?.id - : fromAccount?.id; - - const providerRedirectURLSearch = new URLSearchParams(); - - providerRedirectFromAccountId && - providerRedirectURLSearch.set("accountId", providerRedirectFromAccountId); - - if (provider === "moonpay") { - const moonpayURL = generateMoonpayUrl({ - base: exchangeRate?.providerURL || "", - args: getExchangeSDKParams(), - }); - - exchangeRate?.providerURL && providerRedirectURLSearch.set("goToURL", moonpayURL.toString()); - } else { - exchangeRate?.providerURL && - providerRedirectURLSearch.set("customDappUrl", exchangeRate.providerURL || ""); - } - - providerRedirectURLSearch.set("returnTo", "/swap"); - return providerRedirectURLSearch; - }, [ - walletState, - provider, - swapTransaction.swap.from, - exchangeRate?.providerURL, - generateMoonpayUrl, - getExchangeSDKParams, - walletApiPartnerList?.enabled, - walletApiPartnerList?.params?.list, - ]); - - const refreshIdle = useCallback(() => { - idleState && setIdleState(false); - idleTimeout.current && clearInterval(idleTimeout.current); - idleTimeout.current = setTimeout(() => { - setIdleState(true); - }, idleTime); - }, [idleState]); - - const redirectToProviderApp = useCallback( - (provider: string = ""): void => { - const { providerURL } = exchangeRate ?? {}; - const from = swapTransaction.swap.from; - const fromAccountId = from.parentAccount?.id || from.account?.id; - - const pathname = `/platform/${getProviderName(provider).toLowerCase()}`; - - const account = accounts.find(a => a.id === fromAccountId); - if (!account) return; - const parentAccount = isTokenAccount(account) - ? getParentAccount(account, accounts) - : undefined; - - const accountId = - walletApiPartnerList?.enabled && walletApiPartnerList?.params?.list.includes(provider) - ? accountToWalletAPIAccount(walletState, account, parentAccount)?.id - : fromAccountId; - - const state: { - returnTo: string; - accountId?: string; - goToURL?: string; - customDappUrl?: string; - } = { - returnTo: "/swap", - accountId, - customDappUrl: providerURL, - }; - - if (provider === "moonpay") { - const moonpayURL = generateMoonpayUrl({ - base: exchangeRate?.providerURL || "", - args: getExchangeSDKParams(), - }); - state.customDappUrl = undefined; - state.goToURL = moonpayURL.toString(); - } - - history.push({ - // This looks like an issue, the proper signature is: push(path, [state]) - (function) Pushes a new entry onto the history stack - pathname, - state, - }); - }, - [ - walletState, - accounts, - exchangeRate, - generateMoonpayUrl, - getExchangeSDKParams, - history, - swapTransaction.swap.from, - walletApiPartnerList?.enabled, - walletApiPartnerList?.params?.list, - ], - ); - - useEffect(() => { - if (swapTransaction.swap.rates.status === "success") { - refreshIdle(); - } - }, [refreshIdle, swapTransaction.swap.rates.status]); - - useEffect(() => { - dispatch(updateTransactionAction(swapTransaction.transaction)); - }, [swapTransaction.transaction, dispatch]); - - useEffect(() => { - // Whenever an account is added, reselect the currency to pick a default target account. - // (possibly the one that got created) - if (swapTransaction.swap.to.currency && !swapTransaction.swap.to.account) { - swapTransaction.setToCurrency(swapTransaction.swap.to.currency); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [accounts]); - - // Track errors - useEffect( - () => { - (swapError || swapWarning) && - trackSwapError(swapError! || swapWarning!, { - page: "Page Swap Form", - ...swapDefaultTrack, - sourcecurrency: swapTransaction.swap.from.currency?.name, - provider, - }); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [swapError, swapWarning], - ); - - const isSwapReady = - !swapTransaction.bridgePending && - exchangeRatesState.status !== "loading" && - swapTransaction.transaction && - !swapError && - exchangeRate && - swapTransaction.swap.to.account && - swapTransaction.swap.from.amount && - swapTransaction.swap.from.amount.gt(0); - - const onSubmit = () => { - if (!exchangeRate) return; - - track("button_clicked2", { - button: "Request", - page: "Page Swap Form", - ...swapDefaultTrack, - sourceCurrency: sourceCurrency?.name, - targetCurrency: targetCurrency?.name, - partner: provider, - }); - - if (provider && DAPP_PROVIDERS.includes(provider)) { - redirectToProviderApp(provider); - } else { - // Fix LIVE-9064, prevent the transaction from being updated when using useAllAmount - // FIX LIVE-11283, Do not do this for polkadot as it is required to have transferAllowDeath set checked - swapTransaction.transaction && swapTransaction.transaction.family !== "polkadot" - ? (swapTransaction.transaction.useAllAmount = false) - : null; - // Fix LIVE-11660, remove the margin from thec fees - swapTransaction.transaction && swapTransaction.transaction.family === "evm" - ? (swapTransaction.transaction.additionalFees = undefined) - : null; - setDrawer( - ExchangeDrawer, - { - swapTransaction, - exchangeRate, - }, - { - preventBackdropClick: true, - }, - ); - } - }; - - const sourceAccount = swapTransaction.swap.from.account; - const sourceCurrency = swapTransaction.swap.from.currency; - const targetCurrency = swapTransaction.swap.to.currency; - - useEffect(() => { - if (!exchangeRate) { - return; - } - swapTransaction.swap.updateSelectedRate(exchangeRate); - // suppressing as swapTransaction is not memoized and causes infinite loop - // eslint-disable-next-line - }, [exchangeRate]); - - const untickMax = () => { - swapTransaction.transaction?.useAllAmount ? swapTransaction.toggleMax() : null; - }; - - const setFromAccount = (account: AccountLike | undefined) => { - untickMax(); - swapTransaction.setFromAccount(account); - }; - - const setFromAmount = useCallback( - (amount: BigNumber) => { - swapTransaction.setFromAmount(amount); - }, - [swapTransaction], - ); - - const setToCurrency = (currency: TokenCurrency | CryptoCurrency | undefined) => { - swapTransaction.setToCurrency(currency); - }; - - const toggleMax = () => { - swapTransaction.toggleMax(); - }; - - const reverseSwap = () => { - untickMax(); - swapTransaction.reverseSwap(); - }; - - const localManifest = useLocalLiveAppManifest(swapLiveAppManifestID || undefined); - const remoteManifest = useRemoteLiveAppManifest(swapLiveAppManifestID || undefined); - - const manifest = localManifest || remoteManifest; - useSwapLiveAppHook({ - isSwapLiveAppEnabled: isSwapLiveAppEnabled.enabled, - manifestID: swapLiveAppManifestID, - swapTransaction, - updateSwapWebProps: setSwapWebProps, - swapError, - getExchangeSDKParams, - getProviderRedirectURLSearch, - }); - - // used to get the Quotes Status from Demo 1 swap live app - const [quoteState, setQuoteState] = useSwapLiveAppQuoteState({ - amountTo: exchangeRate?.toAmount, - swapError, - counterValue: undefined, - }); - - return ( - - - - {pageState === "empty" && } - - ) : null - } - // Demo 1 props - pageState={pageState} - swapTransaction={swapTransaction} - provider={provider} - // Demo 0 props - disabled={!isSwapReady} - onClick={onSubmit} - /> - - ); -}; - -export default SwapForm; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/hooks/useIsSwapLiveFlagEnabled.ts b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/hooks/useIsSwapLiveFlagEnabled.ts deleted file mode 100644 index b427ffcce66f..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/hooks/useIsSwapLiveFlagEnabled.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { useFeature } from "@ledgerhq/live-common/featureFlags/index"; - -// used to get the value of the Swap Live App flag -export const useIsSwapLiveFlagEnabled = (flag: string): boolean => { - const demoZero = useFeature("ptxSwapLiveAppDemoZero"); - const demoThree = useFeature("ptxSwapLiveAppDemoThree"); - const coreExperiment = useFeature("ptxSwapCoreExperiment"); - const coreExperimentVariant = coreExperiment?.enabled && coreExperiment?.params?.variant; - - if (flag === "ptxSwapLiveAppDemoThree") { - return ( - !!demoThree?.enabled || ["Demo3", "Demo3Thorswap"].includes(coreExperimentVariant as string) - ); - } - - if (flag === "ptxSwapLiveAppDemoZero") { - return !!demoZero?.enabled || coreExperimentVariant === "Demo0"; - } - - if (flag === "ptxSwapLiveAppDemoOne") { - return false; - } - - throw new Error(`Unknown Swap Live App flag ${flag}`); -}; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/hooks/useSwapLiveAppQuoteState.ts b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/hooks/useSwapLiveAppQuoteState.ts deleted file mode 100644 index 3258901c62f7..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/hooks/useSwapLiveAppQuoteState.ts +++ /dev/null @@ -1,31 +0,0 @@ -import BigNumber from "bignumber.js"; -import { useCallback, useState } from "react"; - -export type CustomSwapQuotesState = { - amountTo: BigNumber | undefined; - swapError: Error | undefined; - counterValue: BigNumber | undefined; -}; - -export function useSwapLiveAppQuoteState({ - amountTo, - swapError, - counterValue, -}: CustomSwapQuotesState): [CustomSwapQuotesState, (next: CustomSwapQuotesState) => void] { - const [state, setQuoteState] = useState({ - amountTo, - swapError, - counterValue, - }); - - const updateQuoteState = useCallback( - (next: CustomSwapQuotesState) => { - setQuoteState({ - ...next, // Apply updates provided to function - swapError: swapError || next.swapError, - }); - }, - [swapError], - ); - return [state, updateQuoteState]; -} diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/index.tsx index 58c10bd36595..bdba909f4cd3 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/index.tsx @@ -2,12 +2,10 @@ import React from "react"; import { Route } from "react-router-dom"; import styled, { createGlobalStyle } from "styled-components"; import Box from "~/renderer/components/Box"; -import SwapForm from "./Form"; import SwapHistory from "./History"; import SwapNavbar from "./Navbar"; import { SwapApp } from "./App"; -import { useIsSwapLiveFlagEnabled } from "./hooks/useIsSwapLiveFlagEnabled"; const Body = styled(Box)` flex: 1; `; @@ -48,16 +46,12 @@ const GlobalStyle = createGlobalStyle` `; const Swap2 = () => { - const isDemo3Enabled = useIsSwapLiveFlagEnabled("ptxSwapLiveAppDemoThree"); - - const SwapPage = isDemo3Enabled ? SwapApp : SwapForm; - return (
- +
diff --git a/apps/ledger-live-desktop/src/renderer/screens/swapWeb/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/swapWeb/index.tsx index 4b238e995e5f..81e2947e26c0 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/swapWeb/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/swapWeb/index.tsx @@ -1,16 +1,16 @@ +import { useDebounce } from "@ledgerhq/live-common/hooks/useDebounce"; +import { useRemoteLiveAppManifest } from "@ledgerhq/live-common/platform/providers/RemoteLiveAppProvider/index"; +import { useLocalLiveAppManifest } from "@ledgerhq/live-common/wallet-api/LocalLiveAppProvider/index"; import React from "react"; import { useSelector } from "react-redux"; +import { useHistory, useLocation } from "react-router-dom"; import Card from "~/renderer/components/Box/Card"; -import { counterValueCurrencySelector, languageSelector } from "~/renderer/reducers/settings"; -import { useRemoteLiveAppManifest } from "@ledgerhq/live-common/platform/providers/RemoteLiveAppProvider/index"; +import { WebviewProps } from "~/renderer/components/Web3AppWebview/types"; import WebPlatformPlayer from "~/renderer/components/WebPlatformPlayer"; import useTheme from "~/renderer/hooks/useTheme"; -import { useHistory, useLocation } from "react-router-dom"; -import { WebviewProps } from "~/renderer/components/Web3AppWebview/types"; -import { useDebounce } from "@ledgerhq/live-common/hooks/useDebounce"; +import { counterValueCurrencySelector, languageSelector } from "~/renderer/reducers/settings"; +import { UnableToLoadSwapLiveError } from "~/renderer/screens/exchange/Swap2/Form/SwapWebViewDemo3"; import { captureException } from "~/sentry/renderer"; -import { UnableToLoadSwapLiveError } from "~/renderer/screens/exchange/Swap2/Form/SwapWebView"; -import { useLocalLiveAppManifest } from "@ledgerhq/live-common/wallet-api/LocalLiveAppProvider/index"; const DEFAULT_SWAP_APP_ID = "swapWeb"; diff --git a/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsCurrencySupported.ts b/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsCurrencySupported.ts deleted file mode 100644 index 8629941a598b..000000000000 --- a/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsCurrencySupported.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { CryptoOrTokenCurrency } from "@ledgerhq/types-cryptoassets"; -import { isCryptoCurrency } from "../../../../currencies"; - -type UseIsCurrencySupportedProps = { - currencyFrom?: CryptoOrTokenCurrency; - params: { - families?: Array; - currencies?: Array; - }; - defaultValue: boolean; -}; - -export function useIsCurrencySupported({ - currencyFrom, - params, - defaultValue, -}: UseIsCurrencySupportedProps) { - const { families, currencies } = params || {}; - - if (!currencyFrom || (!families && !currencies)) { - return defaultValue; - } - - const familyOfCurrencyFrom = isCryptoCurrency(currencyFrom) - ? currencyFrom.family - : currencyFrom.parentCurrency.family; - - const familyOrCurrencyIsEnabled = - families?.includes(familyOfCurrencyFrom) || currencies?.includes(currencyFrom.id); - - // if families or currencies are defined then check if a family or currency is - // enabled. If neither of these are defined or of length 0 then assume everything is enabled. - return families?.length || currencies?.length ? familyOrCurrencyIsEnabled : true; -} diff --git a/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsSwapLiveApp.test.ts b/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsSwapLiveApp.test.ts index 6c2db751c44c..6f474cba4bb3 100644 --- a/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsSwapLiveApp.test.ts +++ b/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsSwapLiveApp.test.ts @@ -1,7 +1,6 @@ /** * @jest-environment jsdom */ -import { cryptocurrenciesById } from "@ledgerhq/cryptoassets/currencies"; import { renderHook } from "@testing-library/react"; import { useFeature } from "../../../../featureFlags"; import { useIsSwapLiveApp } from "./useIsSwapLiveApp"; @@ -11,8 +10,6 @@ jest.mock("../../../../featureFlags"); const useMockFeature = useFeature as jest.Mock; -const bitcoin = cryptocurrenciesById["bitcoin"]; - describe("useIsSwapLiveApp hook", () => { afterEach(() => { jest.clearAllMocks(); @@ -20,90 +17,60 @@ describe("useIsSwapLiveApp hook", () => { it("returns the enabled flag when currencyFrom is not defined", () => { // Set up the mock to return different values based on input useMockFeature.mockImplementation(flagName => { - if (flagName === "ptxSwapLiveAppDemoZero") { - return { enabled: true }; - } - if (flagName === "ptxSwapLiveAppDemoOne") { + if (flagName === "ptxSwapLiveApp") { return { enabled: false }; } }); - const { result } = renderHook(() => useIsSwapLiveApp({ currencyFrom: undefined })); + const { result } = renderHook(() => useIsSwapLiveApp()); expect(result.current.enabled).toBe(true); }); it("returns the enabled flag when families and currencies are not defined", () => { useMockFeature.mockImplementation(flagName => { - if (flagName === "ptxSwapLiveAppDemoZero") { - return { enabled: true, params: { families: undefined, currencies: undefined } }; - } - if (flagName === "ptxSwapLiveAppDemoOne") { + if (flagName === "ptxSwapLiveApp") { return { enabled: false }; } }); - const { result } = renderHook(() => useIsSwapLiveApp({ currencyFrom: bitcoin })); + const { result } = renderHook(() => useIsSwapLiveApp()); expect(result.current.enabled).toBe(true); }); it("returns true when currencyFrom family is in families array and feature is enabled", () => { useMockFeature.mockImplementation(flagName => { - if (flagName === "ptxSwapLiveAppDemoZero") { - return { enabled: true, params: { families: ["bitcoin"], currencies: [] } }; - } - if (flagName === "ptxSwapLiveAppDemoOne") { + if (flagName === "ptxSwapLiveApp") { return { enabled: false }; } }); - const { result } = renderHook(() => useIsSwapLiveApp({ currencyFrom: bitcoin })); + const { result } = renderHook(() => useIsSwapLiveApp()); expect(result.current.enabled).toBe(true); }); it("returns true when currencyFrom is in currencies array and feature is enabled", () => { useMockFeature.mockImplementation(flagName => { - if (flagName === "ptxSwapLiveAppDemoZero") { - return { enabled: true, params: { families: [], currencies: ["bitcoin"] } }; - } - if (flagName === "ptxSwapLiveAppDemoOne") { + if (flagName === "ptxSwapLiveApp") { return { enabled: false }; } }); - const { result } = renderHook(() => useIsSwapLiveApp({ currencyFrom: bitcoin })); + const { result } = renderHook(() => useIsSwapLiveApp()); expect(result.current.enabled).toBe(true); }); - it("returns false when currencyFrom family is not in families, currencyFrom is not in currencies, and feature is disabled", () => { - useMockFeature.mockImplementation(flagName => { - if (flagName === "ptxSwapLiveAppDemoZero") { - return { enabled: false, params: { families: ["ethereum"], currencies: ["ethereum"] } }; - } - if (flagName === "ptxSwapLiveAppDemoOne") { - return { enabled: false }; - } - }); - - const { result } = renderHook(() => useIsSwapLiveApp({ currencyFrom: bitcoin })); - - expect(result.current.enabled).toBe(false); - }); - it("returns enabled flag if both families and currencies are empty arrays", () => { useMockFeature.mockImplementation(flagName => { - if (flagName === "ptxSwapLiveAppDemoZero") { - return { enabled: true, params: { families: [], currencies: [] } }; - } - if (flagName === "ptxSwapLiveAppDemoOne") { + if (flagName === "ptxSwapLiveApp") { return { enabled: false }; } }); - const { result } = renderHook(() => useIsSwapLiveApp({ currencyFrom: bitcoin })); + const { result } = renderHook(() => useIsSwapLiveApp()); expect(result.current.enabled).toBe(true); }); diff --git a/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsSwapLiveApp.ts b/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsSwapLiveApp.ts index 6bbcfeaac2c4..cf014703d50d 100644 --- a/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsSwapLiveApp.ts +++ b/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useIsSwapLiveApp.ts @@ -1,34 +1,12 @@ -import { CryptoOrTokenCurrency } from "@ledgerhq/types-cryptoassets"; import { useCallback, useState } from "react"; -import { useIsCurrencySupported } from "./useIsCurrencySupported"; -import { useSwapLiveConfig } from "./useSwapLiveConfig"; -type Props = { - currencyFrom?: CryptoOrTokenCurrency; -}; - -export function useIsSwapLiveApp({ currencyFrom }: Props) { - const ptxSwapLiveApp = useSwapLiveConfig(); - const [crashed, setHasCrashed] = useState(false); +export function useIsSwapLiveApp() { + const [, setHasCrashed] = useState(false); const onLiveAppCrashed = useCallback(() => setHasCrashed(true), []); - const isEnabled = !!ptxSwapLiveApp?.enabled; - const { families, currencies } = ptxSwapLiveApp?.params ?? {}; - - const isCurrencySupported = useIsCurrencySupported({ - params: { - families, - currencies, - }, - currencyFrom, - defaultValue: !!isEnabled, - }); - - const liveAppAvailable = Boolean(isEnabled && isCurrencySupported && !crashed); - return { - enabled: liveAppAvailable, + enabled: true, onLiveAppCrashed, }; } diff --git a/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useSwapLiveConfig.test.ts b/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useSwapLiveConfig.test.ts index f67fe374f076..68d727593447 100644 --- a/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useSwapLiveConfig.test.ts +++ b/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useSwapLiveConfig.test.ts @@ -18,12 +18,7 @@ describe("useSwapLiveConfig", () => { { enabled: boolean; params: { manifest_id: string; variant?: string } } | undefined >[], ) => { - const flagsKeys = [ - "ptxSwapLiveAppDemoZero", - "ptxSwapLiveAppDemoOne", - "ptxSwapLiveAppDemoThree", - "ptxSwapCoreExperiment", - ]; + const flagsKeys = ["ptxSwapLiveApp"]; useMockFeature.mockImplementation(flagName => flags[flagsKeys.indexOf(flagName)] ?? null); }; @@ -32,167 +27,12 @@ describe("useSwapLiveConfig", () => { jest.clearAllMocks(); }); - it("should highest priority flag if all features have the same enabled state", () => { - setupFeatureFlagsMock([ - { enabled: true, params: { manifest_id: "demo_0" } }, - { enabled: true, params: { manifest_id: "demo_1" } }, - { enabled: true, params: { manifest_id: "demo_3" } }, - ]); - const { result } = renderHook(() => useSwapLiveConfig()); - - expect(result.current).not.toBeNull(); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - expect((result.current?.params as any)?.manifest_id).toEqual("demo_0"); - }); - - it("should return null if both features are disabled", () => { - setupFeatureFlagsMock([{ enabled: false }, { enabled: false }, { enabled: false }]); - const { result } = renderHook(() => useSwapLiveConfig()); - expect(result.current).toBeNull(); - }); - - it("should return demoZero if only demoZero is enabled", () => { - setupFeatureFlagsMock([ - { - enabled: true, - params: { manifest_id: "swap-live-app-demo-0" }, - }, - { enabled: false }, - { enabled: false }, - ]); - const { result } = renderHook(() => useSwapLiveConfig()); - expect(result.current).toEqual({ - enabled: true, - params: { manifest_id: "swap-live-app-demo-0" }, - }); - }); - - it("should return demoOne if only demoOne is enabled", () => { - setupFeatureFlagsMock([ - { enabled: false }, - { - enabled: true, - params: { manifest_id: "swap-live-app-demo-1" }, - }, - { enabled: false }, - ]); - const { result } = renderHook(() => useSwapLiveConfig()); - expect(result.current).toEqual({ - enabled: true, - params: { manifest_id: "swap-live-app-demo-1" }, - }); - }); - - it("should return demoThree if only demoOne is enabled", () => { - setupFeatureFlagsMock([ - { enabled: false }, - { - enabled: true, - params: { manifest_id: "swap-live-app-demo-3" }, - }, - { enabled: false }, - ]); - + it("should return demoThree config", () => { + setupFeatureFlagsMock([{ enabled: true, params: { manifest_id: "swap-live-app-demo-3" } }]); const { result } = renderHook(() => useSwapLiveConfig()); expect(result.current).toEqual({ enabled: true, params: { manifest_id: "swap-live-app-demo-3" }, }); }); - - it("should return config when ptxSwapCoreExperiment has valid variant Demo0", () => { - const expected = { - enabled: true, - params: { manifest_id: "swap-live-app-demo-0", variant: "Demo0" }, - }; - setupFeatureFlagsMock([{ enabled: false }, { enabled: false }, { enabled: false }, expected]); - const { result } = renderHook(() => useSwapLiveConfig()); - expect(result.current).toEqual(expected); - }); - - it("should return config when ptxSwapCoreExperiment has valid variant Demo3", () => { - setupFeatureFlagsMock([ - { enabled: false }, - { enabled: false }, - { enabled: false }, - { enabled: true, params: { manifest_id: "swap-live-app-demo-3", variant: "Demo3" } }, - ]); - const { result } = renderHook(() => useSwapLiveConfig()); - expect(result.current).toEqual({ - enabled: true, - params: { manifest_id: "swap-live-app-demo-3", variant: "Demo3" }, - }); - }); - - it("should return config when ptxSwapCoreExperiment has valid variant Demo3Thorswap", () => { - setupFeatureFlagsMock([ - { enabled: false }, - { enabled: false }, - { enabled: false }, - { enabled: true, params: { manifest_id: "swap-live-app-demo-3", variant: "Demo3Thorswap" } }, - ]); - const { result } = renderHook(() => useSwapLiveConfig()); - expect(result.current).toEqual({ - enabled: true, - params: { manifest_id: "swap-live-app-demo-3", variant: "Demo3Thorswap" }, - }); - }); - - it("should return demoZero if demoThree and are enabled", () => { - setupFeatureFlagsMock([ - { enabled: true, params: { manifest_id: "swap-live-app-demo-0" } }, - { enabled: false }, - { enabled: true, params: { manifest_id: "swap-live-app-demo-3" } }, - ]); - const { result } = renderHook(() => useSwapLiveConfig()); - expect(result.current).toEqual({ - enabled: true, - params: { manifest_id: "swap-live-app-demo-0" }, - }); - }); - - it("should return demoZero if all demo flags are enabled", () => { - setupFeatureFlagsMock([ - { enabled: true, params: { manifest_id: "swap-live-app-demo-0" } }, - { enabled: true, params: { manifest_id: "swap-live-app-demo-1" } }, - { enabled: true, params: { manifest_id: "swap-live-app-demo-3" } }, - ]); - const { result } = renderHook(() => useSwapLiveConfig()); - expect(result.current).toEqual({ - enabled: true, - params: { manifest_id: "swap-live-app-demo-0" }, - }); - }); - - it("should prioritize demoZero over demo flags if all are enabled", () => { - setupFeatureFlagsMock([ - { enabled: true, params: { manifest_id: "swap-live-app-demo-0" } }, - { enabled: true, params: { manifest_id: "swap-live-app-demo-1" } }, - { enabled: true, params: { manifest_id: "swap-live-app-demo-3" } }, - { enabled: true, params: { manifest_id: "swap-live-app-demo-3", variant: "Demo3" } }, - ]); - const { result } = renderHook(() => useSwapLiveConfig()); - expect(result.current).toEqual({ - enabled: true, - params: { manifest_id: "swap-live-app-demo-0" }, - }); - }); - - it("should return null when coreExperiment is enabled but has no variant", () => { - setupFeatureFlagsMock([ - { enabled: false }, - { enabled: false }, - { enabled: false }, - { enabled: true, params: { manifest_id: "core-experiment" } }, - ]); - const { result } = renderHook(() => useSwapLiveConfig()); - expect(result.current).toBeNull(); - }); - - it("should return null when all flags are undefined", () => { - setupFeatureFlagsMock([undefined, undefined, undefined, undefined]); - const { result } = renderHook(() => useSwapLiveConfig()); - expect(result.current).toBeNull(); - }); }); diff --git a/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useSwapLiveConfig.ts b/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useSwapLiveConfig.ts index 648628bf8ccb..cb66910105dc 100644 --- a/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useSwapLiveConfig.ts +++ b/libs/ledger-live-common/src/exchange/swap/hooks/live-app-migration/useSwapLiveConfig.ts @@ -1,38 +1,15 @@ -import { Feature_PtxSwapCoreExperiment } from "@ledgerhq/types-live/lib/feature"; import { useFeature } from "../../../../featureFlags"; -// check if the variant is valid for core rollout experiment -export type CoreExperimentParams = NonNullable; -export type ValidVariant = CoreExperimentParams["variant"]; - -// used to enable the Swap Live App globally +/** + * This hook is used to retrieve the configuration for the Swap Live App. + * The `ptxSwapLiveApp` feature flag is always true, but it is used + * to obtain the manifest ID that loads the URL for the live app in production, + * stg, or ppr environments. + * + * @returns The feature flag configuration for `ptxSwapLiveApp`. + */ export function useSwapLiveConfig() { - const demoThree = useFeature("ptxSwapLiveAppDemoThree"); - const demoOne = useFeature("ptxSwapLiveAppDemoOne"); - const demoZero = useFeature("ptxSwapLiveAppDemoZero"); - const coreExperiment = useFeature("ptxSwapCoreExperiment"); - - // const validVariants: readonly ValidVariant[] = ["Demo0", "Demo3", "Demo3Thorswap"] as const; - - if (demoZero?.enabled) { - return demoZero; - } - - if (demoThree?.enabled) { - return demoThree; - } - - if (coreExperiment?.enabled) { - const variant = coreExperiment?.params?.variant; - if (!variant || !(variant satisfies ValidVariant)) { - return null; - } - return coreExperiment; - } - - if (demoOne?.enabled) { - return demoOne; - } + const config = useFeature("ptxSwapLiveApp"); - return null; + return config; } diff --git a/libs/ledger-live-common/src/exchange/swap/hooks/v5/useFilteredProviders.ts b/libs/ledger-live-common/src/exchange/swap/hooks/v5/useFilteredProviders.ts index dccab89f981e..33a10ce8f496 100644 --- a/libs/ledger-live-common/src/exchange/swap/hooks/v5/useFilteredProviders.ts +++ b/libs/ledger-live-common/src/exchange/swap/hooks/v5/useFilteredProviders.ts @@ -1,16 +1,12 @@ +import { getEnv } from "@ledgerhq/live-env"; import { useCallback, useEffect, useState } from "react"; -import { useFeature } from "../../../../featureFlags"; import { fetchAndMergeProviderData } from "../../../providers/swap"; -import { getEnv } from "@ledgerhq/live-env"; export const useFilteredProviders = () => { const [providers, setProviders] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - const ptxSwapMoonpayProviderFlag = useFeature("ptxSwapMoonpayProvider"); - const ptxSwapExodusProviderFlag = useFeature("ptxSwapExodusProvider"); - const fetchProviders = useCallback(async () => { try { const ledgerSignatureEnv = getEnv("MOCK_EXCHANGE_TEST_CONFIG") ? "test" : "prod"; @@ -18,13 +14,7 @@ export const useFilteredProviders = () => { const data = await fetchAndMergeProviderData({ ledgerSignatureEnv, partnerSignatureEnv }); - let filteredProviders = Object.keys(data); - if (!ptxSwapMoonpayProviderFlag?.enabled) { - filteredProviders = filteredProviders.filter(provider => provider !== "moonpay"); - } - if (!ptxSwapExodusProviderFlag?.enabled) { - filteredProviders = filteredProviders.filter(provider => provider !== "exodus"); - } + const filteredProviders = Object.keys(data); setProviders(filteredProviders); } catch (error) { @@ -32,7 +22,7 @@ export const useFilteredProviders = () => { } finally { setLoading(false); } - }, [ptxSwapMoonpayProviderFlag, ptxSwapExodusProviderFlag]); + }, []); useEffect(() => { fetchProviders(); diff --git a/libs/ledger-live-common/src/featureFlags/defaultFeatures.ts b/libs/ledger-live-common/src/featureFlags/defaultFeatures.ts index 51c16cd292f3..f4389da7820a 100644 --- a/libs/ledger-live-common/src/featureFlags/defaultFeatures.ts +++ b/libs/ledger-live-common/src/featureFlags/defaultFeatures.ts @@ -90,7 +90,6 @@ export const CURRENCY_DEFAULT_FEATURES = { */ export const DEFAULT_FEATURES: Features = { ...CURRENCY_DEFAULT_FEATURES, - brazeLearn: DEFAULT_FEATURE, portfolioExchangeBanner: DEFAULT_FEATURE, postOnboardingAssetsTransfer: DEFAULT_FEATURE, @@ -399,38 +398,13 @@ export const DEFAULT_FEATURES: Features = { }, ptxCard: DEFAULT_FEATURE, - ptxSwapLiveAppDemoZero: { - enabled: false, - params: { - manifest_id: "swap-live-app-demo-0", - }, - }, - - ptxSwapLiveAppDemoOne: { - enabled: false, - params: { - manifest_id: "swap-live-app-demo-1", - }, - }, - - ptxSwapLiveAppDemoThree: { - enabled: false, + ptxSwapLiveApp: { + enabled: true, params: { manifest_id: "swap-live-app-demo-3", }, }, - ptxSwapCoreExperiment: { - enabled: false, - params: { - variant: "Demo0", - manifest_id: "swap-live-app-demo-0", - }, - }, - - ptxSwapMoonpayProvider: DEFAULT_FEATURE, - ptxSwapExodusProvider: DEFAULT_FEATURE, - llmAnalyticsOptInPrompt: { enabled: false, params: { diff --git a/libs/ledgerjs/packages/types-live/src/feature.ts b/libs/ledgerjs/packages/types-live/src/feature.ts index 235167b57f03..ae95db518700 100644 --- a/libs/ledgerjs/packages/types-live/src/feature.ts +++ b/libs/ledgerjs/packages/types-live/src/feature.ts @@ -168,12 +168,7 @@ export type Features = CurrencyFeatures & { fetchAdditionalCoins: Feature_FetchAdditionalCoins; ptxCard: DefaultFeature; ptxSwapLiveAppMobile: DefaultFeature; - ptxSwapLiveAppDemoZero: Feature_PtxSwapLiveAppDemoZero; - ptxSwapLiveAppDemoOne: Feature_PtxSwapLiveAppDemoZero; - ptxSwapLiveAppDemoThree: Feature_PtxSwapLiveAppDemoZero; - ptxSwapCoreExperiment: Feature_PtxSwapCoreExperiment; - ptxSwapMoonpayProvider: Feature_PtxSwapMoonpayProvider; - ptxSwapExodusProvider: Feature_PtxSwapExodusProvider; + ptxSwapLiveApp: Feature_PtxSwapLiveApp; ptxSwapReceiveTRC20WithoutTrx: Feature_PtxSwapReceiveTRC20WithoutTrx; flexibleContentCards: Feature_FlexibleContentCards; llmAnalyticsOptInPrompt: Feature_LlmAnalyticsOptInPrompt; @@ -471,18 +466,6 @@ export type Feature_RatingsPrompt = Feature<{ }>; export type Feature_PtxSwapLiveApp = Feature<{ - currencies?: Array; - families?: Array; -}>; - -export type Feature_PtxSwapLiveAppDemoZero = Feature<{ - manifest_id: string; - currencies?: string[]; - families?: string[]; -}>; - -export type Feature_PtxSwapCoreExperiment = Feature<{ - variant: "Demo0" | "Demo3" | "Demo3Thorswap"; manifest_id: string; currencies?: string[]; families?: string[]; @@ -556,8 +539,6 @@ export type Feature_PtxServiceCtaExchangeDrawer = DefaultFeature; export type Feature_PtxServiceCtaScreens = DefaultFeature; export type Feature_PortfolioExchangeBanner = DefaultFeature; export type Feature_BrazeLearn = DefaultFeature; -export type Feature_PtxSwapMoonpayProvider = DefaultFeature; -export type Feature_PtxSwapExodusProvider = DefaultFeature; export type Feature_PtxSwapReceiveTRC20WithoutTrx = DefaultFeature; export type Feature_FlexibleContentCards = DefaultFeature; export type Feature_MyLedgerDisplayAppDeveloperName = DefaultFeature;