diff --git a/.changeset/orange-turkeys-wait.md b/.changeset/orange-turkeys-wait.md new file mode 100644 index 000000000000..0fbded1abcec --- /dev/null +++ b/.changeset/orange-turkeys-wait.md @@ -0,0 +1,8 @@ +--- +"@ledgerhq/types-live": minor +"ledger-live-desktop": minor +"ledger-live-mobile": minor +"@ledgerhq/live-common": minor +--- + +Add link param to mevProtection ff diff --git a/apps/ledger-live-desktop/src/renderer/screens/settings/SettingsSection.tsx b/apps/ledger-live-desktop/src/renderer/screens/settings/SettingsSection.tsx index 8245f8bd969c..e2f505a1c8b2 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/settings/SettingsSection.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/settings/SettingsSection.tsx @@ -2,6 +2,9 @@ import React from "react"; import styled from "styled-components"; import { rgba } from "~/renderer/styles/helpers"; import Box, { Card } from "~/renderer/components/Box"; +import { Flex, Link } from "@ledgerhq/react-ui"; +import { openURL } from "~/renderer/linking"; + export const SettingsSection = styled(Card).attrs(() => ({ p: 0, }))``; @@ -94,6 +97,8 @@ type SettingsSectionRowProps = { childrenContainerStyle?: React.CSSProperties; dataTestId?: string; id?: string; + externalUrl?: string; + linkText?: string; }; export const SettingsSectionRow = ({ title, @@ -106,6 +111,8 @@ export const SettingsSectionRow = ({ childrenContainerStyle, dataTestId, id, + externalUrl, + linkText, }: SettingsSectionRowProps) => ( {desc} + {externalUrl && ( + + openURL(externalUrl)} + > + {linkText} + + + )} {children} diff --git a/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/index.tsx index 5e81b0d0437d..45ef06c1de18 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/settings/sections/General/index.tsx @@ -25,7 +25,8 @@ const SectionGeneral = () => { const { t } = useTranslation(); useInitSupportedCounterValues(); const lldAnalyticsOptInPromptFlag = useFeature("lldAnalyticsOptInPrompt"); - + const llMevProtectionFeatureFlag = useFeature("llMevProtection"); + const mevLearnMoreLink = llMevProtectionFeatureFlag?.params?.link?.trim() || undefined; return ( <> @@ -97,6 +98,8 @@ const SectionGeneral = () => { desc={t("settings.display.mevProtectionDesc")} dataTestId="setting-mevProtection" id="setting-mevProtection" + linkText={t("settings.display.mevProtectionLearnMore")} + externalUrl={mevLearnMoreLink} > diff --git a/apps/ledger-live-desktop/static/i18n/en/app.json b/apps/ledger-live-desktop/static/i18n/en/app.json index 638d6f09cb42..36cefc5c1f45 100644 --- a/apps/ledger-live-desktop/static/i18n/en/app.json +++ b/apps/ledger-live-desktop/static/i18n/en/app.json @@ -4154,7 +4154,8 @@ "walletSync": "Ledger Sync", "walletSyncDesc": "Sync your Ledger Live crypto accounts across different phones and computers.", "mevProtection": "MEV Protection", - "mevProtectionDesc": "Enable MEV Protection for more reliable transactions on Ethereum", + "mevProtectionDesc": "Enable MEV Protection for more reliable transactions on Ethereum.", + "mevProtectionLearnMore": "Privacy notice", "marketPerformanceWidget": "Market Performance Widget", "marketPerformanceWidgetDesc": "Enable this feature to view the top gainers and losers over selected timeframes on the portfolio page." }, diff --git a/apps/ledger-live-mobile/src/locales/en/common.json b/apps/ledger-live-mobile/src/locales/en/common.json index 64487a73fa99..0aebe546e02d 100644 --- a/apps/ledger-live-mobile/src/locales/en/common.json +++ b/apps/ledger-live-mobile/src/locales/en/common.json @@ -2909,7 +2909,8 @@ "analytics": "Analytics", "analyticsDesc": "Enable Ledger to collect app usage data to help measure Ledger Live’s performance and enhance both the app and your experience.", "mevProtection": "MEV Protection", - "mevProtectionDesc": "Enable MEV Protection for more reliable transactions on Ethereum", + "mevProtectionDesc": "Enable MEV Protection for more reliable transactions on Ethereum.", + "mevProtectionLearnMore": "Privacy notice", "personalizedRecommendations": "Personalized experience", "personalizedRecommendationsDesc": "Enable Ledger to collect app usage data to provide personalized recommendations and content that match your preferences and to help measure the performance of our marketing campaigns.", "analyticsModal": { diff --git a/apps/ledger-live-mobile/src/screens/Settings/General/MevProtection.tsx b/apps/ledger-live-mobile/src/screens/Settings/General/MevProtection.tsx index 070ac9fb7502..8f733602c2d3 100644 --- a/apps/ledger-live-mobile/src/screens/Settings/General/MevProtection.tsx +++ b/apps/ledger-live-mobile/src/screens/Settings/General/MevProtection.tsx @@ -1,19 +1,33 @@ -import React, { useCallback } from "react"; +import React, { ReactNode, useCallback } from "react"; import { useSelector, useDispatch } from "react-redux"; import { useTranslation } from "react-i18next"; -import { Switch } from "@ledgerhq/native-ui"; +import { Flex, Text, Switch } from "@ledgerhq/native-ui"; import SettingsRow from "~/components/SettingsRow"; import { setMevProtection } from "~/actions/settings"; import { mevProtectionSelector } from "~/reducers/settings"; import Track from "~/analytics/Track"; import { track } from "~/analytics"; +import { useFeature } from "@ledgerhq/live-common/featureFlags/index"; +import { Linking } from "react-native"; +import styled from "styled-components/native"; +const StyledText = styled(Text).attrs(() => ({ + color: "neutral.c70", +}))` + text-decoration: underline; + text-decoration-color: ${({ theme }) => theme.colors.neutral.c70}; +`; const MevProtectionRow = () => { const { t } = useTranslation(); const mevProctection = useSelector(mevProtectionSelector); const dispatch = useDispatch(); + const llMevProtectionFeatureFlag = useFeature("llMevProtection"); + const mevLearnMoreLink = llMevProtectionFeatureFlag?.params?.link?.trim() || undefined; + + const onPressLink = (url: string) => Linking.openURL(url); + const toggleMevProtection = useCallback( (value: boolean) => { dispatch(setMevProtection(value)); @@ -31,13 +45,31 @@ const MevProtectionRow = () => { [dispatch], ); + const description: ReactNode = ( + + + {t("settings.display.mevProtectionDesc")} + + {mevLearnMoreLink && ( + onPressLink(mevLearnMoreLink)} + variant="body" + fontWeight="medium" + > + {t("settings.display.mevProtectionLearnMore")} + + )} + + ); + return ( <> toggleMevProtection(!mevProctection)} /> diff --git a/libs/ledger-live-common/src/featureFlags/defaultFeatures.ts b/libs/ledger-live-common/src/featureFlags/defaultFeatures.ts index 99012d2e12e0..822398217688 100644 --- a/libs/ledger-live-common/src/featureFlags/defaultFeatures.ts +++ b/libs/ledger-live-common/src/featureFlags/defaultFeatures.ts @@ -501,7 +501,10 @@ export const DEFAULT_FEATURES: Features = { warningVisible: true, }, }, - llMevProtection: DEFAULT_FEATURE, + llMevProtection: { + ...DEFAULT_FEATURE, + params: { link: null }, + }, llmNetworkBasedAddAccountFlow: DEFAULT_FEATURE, llCounterValueGranularitiesRates: { ...DEFAULT_FEATURE, diff --git a/libs/ledgerjs/packages/types-live/src/feature.ts b/libs/ledgerjs/packages/types-live/src/feature.ts index 94f8faa7f052..ffc41a222f93 100644 --- a/libs/ledgerjs/packages/types-live/src/feature.ts +++ b/libs/ledgerjs/packages/types-live/src/feature.ts @@ -199,7 +199,7 @@ export type Features = CurrencyFeatures & { llmMemoTag: Feature_MemoTag; lldMemoTag: Feature_MemoTag; ldmkTransport: Feature_LdmkTransport; - llMevProtection: DefaultFeature; + llMevProtection: Feature_LlMevProtection; llmNetworkBasedAddAccountFlow: DefaultFeature; llCounterValueGranularitiesRates: Feature_LlCounterValueGranularitiesRates; llmRebornLP: Feature_LlmRebornLP; @@ -549,6 +549,10 @@ export type Feature_LlCounterValueGranularitiesRates = Feature<{ hourly: number; }>; +export type Feature_LlMevProtection = Feature<{ + link: string | null; +}>; + export type Feature_CounterValue = DefaultFeature; export type Feature_MockFeature = DefaultFeature; export type Feature_DisableNftSend = DefaultFeature;