Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Support: FAT-597 quick fix for 0x5515 error #1741

Merged
merged 15 commits into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fifty-garlics-marry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"live-mobile": patch
---

Fix for locked device error
6 changes: 6 additions & 0 deletions .changeset/little-parrots-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ledgerhq/live-common": patch
"@ledgerhq/errors": patch
---

Fix for locked device error
5 changes: 5 additions & 0 deletions .changeset/selfish-lobsters-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ledger-live-desktop": patch
---

Fix for locked device error
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ const CustomImageDeviceAction: React.FC<Props> = withRemountableWrapper(props =>
) : isError ? (
<Flex flexDirection="column" alignItems="center">
{renderError({
t,
error,
device: device ?? undefined,
...(isRefusedOnStaxError
? { Icon: Icons.CircledAlertMedium, iconColor: "warning.c100" }
: {}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
renderSecureTransferDeviceConfirmation,
renderAllowLanguageInstallation,
renderInstallingLanguage,
renderLockedDeviceError,
} from "./rendering";

type Props<R, H, P> = {
Expand Down Expand Up @@ -73,6 +74,7 @@ export const DeviceActionDefaultRendering = <R, H, P>({
appAndVersion,
device,
unresponsive,
isLocked,
error,
isLoading,
allowManagerRequestedWording,
Expand Down Expand Up @@ -241,6 +243,7 @@ export const DeviceActionDefaultRendering = <R, H, P>({

if (inWrongDeviceForAccount) {
return renderInWrongAppForAccount({
t,
onRetry,
accountName: inWrongDeviceForAccount.accountName,
});
Expand All @@ -253,13 +256,15 @@ export const DeviceActionDefaultRendering = <R, H, P>({
error instanceof UpdateYourApp
) {
return renderError({
t,
error,
managerAppName: error.managerAppName,
});
}

if (error instanceof LatestFirmwareVersionRequired) {
return renderError({
t,
error,
requireFirmwareUpdate: true,
});
Expand All @@ -272,6 +277,7 @@ export const DeviceActionDefaultRendering = <R, H, P>({
(error instanceof TransportStatusError && error.message.includes("0x6d06"))
) {
return renderError({
t,
error: new DeviceNotOnboarded(),
withOnboardingCTA: true,
info: true,
Expand All @@ -280,19 +286,27 @@ export const DeviceActionDefaultRendering = <R, H, P>({

if (error instanceof NoSuchAppOnProvider) {
return renderError({
t,
error,
withOpenManager: true,
withExportLogs: true,
});
}

return renderError({
t,
error,
onRetry,
withExportLogs: true,
device: device ?? undefined,
});
}

// Renders an error as long as LLD is using the "event" implementation of device actions
if (isLocked) {
return renderLockedDeviceError({ t, device, onRetry });
}

if ((!isLoading && !device) || unresponsive) {
return renderConnectYourDevice({
modelId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { TokenCurrency } from "@ledgerhq/types-cryptoassets";
import { Transaction, TransactionStatus } from "@ledgerhq/live-common/generated/types";
import { ExchangeRate, Exchange } from "@ledgerhq/live-common/exchange/swap/types";
import { getProviderName } from "@ledgerhq/live-common/exchange/swap/utils/index";
import { WrongDeviceForAccount, UpdateYourApp } from "@ledgerhq/errors";
import { WrongDeviceForAccount, UpdateYourApp, LockedDeviceError } from "@ledgerhq/errors";
import { LatestFirmwareVersionRequired } from "@ledgerhq/live-common/errors";
import { DeviceModelId, getDeviceModel } from "@ledgerhq/devices";
import { Device } from "@ledgerhq/live-common/hw/actions/types";
Expand Down Expand Up @@ -47,7 +47,8 @@ import { SWAP_VERSION } from "~/renderer/screens/exchange/Swap2/utils/index";
import { context } from "~/renderer/drawers/Provider";
import { track } from "~/renderer/analytics/segment";
import { DrawerFooter } from "~/renderer/screens/exchange/Swap2/Form/DrawerFooter";
import { Flex, Icons, Text as TextV3, Log, ProgressLoader } from "@ledgerhq/react-ui";
import { Flex, Icons, Text as TextV3, Log, ProgressLoader, BoxedIcon } from "@ledgerhq/react-ui";
import { LockAltMedium } from "@ledgerhq/react-ui/assets/icons";
import { withV3StyleProvider } from "~/renderer/styles/StyleProviderV3";
import FramedImage from "../CustomImage/FramedImage";

Expand Down Expand Up @@ -483,8 +484,49 @@ export const renderWarningOutdated = ({
</Wrapper>
);

// Quick fix: the error LockedDeviceError should be catched
// inside all the device actions and mapped to an event of type "lockedDevice".
// With this fix, we can catch all the device action error that were not catched upstream.
// If LockedDeviceError is thrown from outside a device action and renderError was not called
// it is still handled by GenericErrorView.
export const renderLockedDeviceError = ({
t,
device,
onRetry,
}: {
t: TFunction;
alexandremgo marked this conversation as resolved.
Show resolved Hide resolved
device?: Device;
onRetry?: () => void;
}) => {
const productName = device ? getDeviceModel(device.modelId).productName : null;

return (
<Wrapper id="error-locked-device">
<Flex mb={5}>
<BoxedIcon size={64} Icon={LockAltMedium} iconSize={24} iconColor="neutral.c100" />
</Flex>
<ErrorTitle>{t("errors.LockedDeviceError.title")}</ErrorTitle>
<ErrorDescription>
{productName
? t("errors.LockedDeviceError.descriptionWithProductName", {
productName,
})
: t("errors.LockedDeviceError.description")}
</ErrorDescription>
<ButtonContainer>
{onRetry ? (
<Button primary onClick={onRetry}>
{t("common.retry")}
</Button>
) : null}
</ButtonContainer>
</Wrapper>
);
};

export const renderError = ({
error,
t,
withOpenManager,
onRetry,
withExportLogs,
Expand All @@ -495,8 +537,10 @@ export const renderError = ({
managerAppName,
requireFirmwareUpdate,
withOnboardingCTA,
device,
}: {
error: Error;
t: TFunction;
withOpenManager?: boolean;
onRetry?: () => void;
withExportLogs?: boolean;
Expand All @@ -507,67 +551,79 @@ export const renderError = ({
managerAppName?: string;
requireFirmwareUpdate?: boolean;
withOnboardingCTA?: boolean;
}) => (
<Wrapper id={`error-${error.name}`}>
<Logo info={info} warning={warning}>
<ErrorIcon size={44} error={error} />
</Logo>
<ErrorTitle>
<TranslatedError error={error} />
</ErrorTitle>
<ErrorDescription>
<TranslatedError error={error} field="description" /> <SupportLinkError error={error} />
</ErrorDescription>
{list ? (
device?: Device;
}) => {
// Redirects from renderError and not from DeviceActionDefaultRendering because renderError
// can be used directly by other component
if (error instanceof LockedDeviceError) {
return renderLockedDeviceError({ t, onRetry, device });
}

return (
<Wrapper id={`error-${error.name}`}>
<Logo info={info} warning={warning}>
<ErrorIcon size={44} error={error} />
</Logo>
<ErrorTitle>
<TranslatedError error={error} />
</ErrorTitle>
<ErrorDescription>
<ol style={{ textAlign: "justify" }}>
<TranslatedError error={error} field="list" />
</ol>
<TranslatedError error={error} field="description" /> <SupportLinkError error={error} />
</ErrorDescription>
) : null}
<ButtonContainer>
{managerAppName || requireFirmwareUpdate ? (
<OpenManagerButton
appName={managerAppName}
updateApp={error instanceof UpdateYourApp}
firmwareUpdate={error instanceof LatestFirmwareVersionRequired}
/>
) : (
<>
{supportLink ? (
<ExternalLinkButton label={<Trans i18nKey="common.getSupport" />} url={supportLink} />
) : null}
{withExportLogs ? (
<ExportLogsButton
title={<Trans i18nKey="settings.exportLogs.title" />}
small={false}
primary={false}
outlineGrey
mx={1}
/>
) : null}
{withOpenManager ? (
<OpenManagerButton mt={0} ml={withExportLogs ? 4 : 0} />
) : onRetry ? (
<Button primary ml={withExportLogs ? 4 : 0} onClick={onRetry}>
<Trans i18nKey="common.retry" />
</Button>
) : null}
{withOnboardingCTA ? <OpenOnboardingBtn /> : null}
</>
)}
</ButtonContainer>
</Wrapper>
);
{list ? (
<ErrorDescription>
<ol style={{ textAlign: "justify" }}>
<TranslatedError error={error} field="list" />
</ol>
</ErrorDescription>
) : null}
<ButtonContainer>
{managerAppName || requireFirmwareUpdate ? (
<OpenManagerButton
appName={managerAppName}
updateApp={error instanceof UpdateYourApp}
firmwareUpdate={error instanceof LatestFirmwareVersionRequired}
/>
) : (
<>
{supportLink ? (
<ExternalLinkButton label={t("common.getSupport")} url={supportLink} />
) : null}
{withExportLogs ? (
<ExportLogsButton
title={t("settings.exportLogs.title")}
small={false}
primary={false}
outlineGrey
mx={1}
/>
) : null}
{withOpenManager ? (
<OpenManagerButton mt={0} ml={withExportLogs ? 4 : 0} />
) : onRetry ? (
<Button primary ml={withExportLogs ? 4 : 0} onClick={onRetry}>
{t("common.retry")}
</Button>
) : null}
{withOnboardingCTA ? <OpenOnboardingBtn /> : null}
</>
)}
</ButtonContainer>
</Wrapper>
);
};

export const renderInWrongAppForAccount = ({
t,
onRetry,
accountName,
}: {
t: TFunction;
onRetry: () => void;
accountName: string;
}) =>
renderError({
t,
error: new WrongDeviceForAccount(null, { accountName }),
withExportLogs: true,
onRetry,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useTranslation } from "react-i18next";
import { renderError } from "~/renderer/components/DeviceAction/rendering";

export type ErrorDisplayProps = {
error: Error;
onRetry?: () => void;
withExportLogs?: boolean;
list?: boolean;
supportLink?: string;
warning?: boolean;
};

const ErrorDisplay = ({
error,
onRetry,
withExportLogs,
list,
supportLink,
warning,
}: ErrorDisplayProps) => {
const { t } = useTranslation();

return renderError({ t, error, onRetry, withExportLogs, list, supportLink, warning });
};

export default ErrorDisplay;
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ const Result = ({
const Root = ({ data, onClose }: Props) => {
const { account, parentAccount, getCoinifyContext, onResult, onCancel } = data;

const { t } = useTranslation();

const tokenCurrency = account && account.type === "TokenAccount" && account.token;

// state
Expand Down Expand Up @@ -138,6 +140,7 @@ const Root = ({ data, onClose }: Props) => {
return (
<Box alignItems={"center"} justifyContent={"center"} p={20}>
{renderError({
t,
error,
})}
</Box>
Expand Down
5 changes: 5 additions & 0 deletions apps/ledger-live-desktop/static/i18n/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -5309,6 +5309,11 @@
"ImageLoadRefusedOnDevice": {
"title": "Image load refused on device (TODO: final wording)",
"description": "If this image wasn't the right fit, you can try again with another image."
},
"LockedDeviceError": {
"title": "Your device is locked",
"description": "Unlock your device and try again.",
"descriptionWithProductName": "Unlock your {{ productName }} and try again."
}
},
"cryptoOrg": {
Expand Down
Loading