Skip to content

Commit

Permalink
🐛(llm): avoid blink on unsynch LLM (#7836)
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasWerey authored Sep 19, 2024
1 parent 332312b commit d9a4644
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 65 deletions.
5 changes: 5 additions & 0 deletions .changeset/shiny-pants-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"live-mobile": patch
---

Avoid blink when LLM is unsync
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJ0cnVzdGNoYWluLWJhY2tlbmQuYXBpLmF3cy5zdGcubGRnLXRlY2guY29tIiwic3ViIjoiMDMyNjk2ZWJkN2MyNzZjYjIwODM4MmNjYTk2Mzg4YWJjNWYxNTBkNDE1YjU5OWY3OTgzZmYzNTc1YmNlNDQxNDAxIiwiYXVkIjpbIkNsb3VkU3luYyIsInRydXN0Y2hhaW4iXSwiZXhwIjoxNzI2NjY1MjUwLCJpYXQiOjE3MjY2NjQ5NDksImp0aSI6IjhkM2JiYTVmLTg1NGYtNDkyNy1iZDFjLWUwMzE1NjE4Y2VmMCIsInBlcm1pc3Npb25zIjp7fSwiZGV2aWNlIjp0cnVlLCJyZWZyZXNoRXhwaXJhdGlvbiI6IjIwMjQtMDktMThUMTQ6MDk6MTBaIn0.wUyEXD488WSbKbdOM7Wk33SjKMzm7VGP3nCGRfTYhgNkI6vNdPrEQnrwKo6uloWsVvL5BrNpBCkd_8GPf2eyZw",
"permissions": {
"000c9ec1a1ab774f7eaeff2b0d4ad695f1fa07ea28d33f5d34126cb1152d6d83f6": {
"m/0'/16'/0'": ["owner"]
}
}
}
27 changes: 27 additions & 0 deletions apps/ledger-live-mobile/__mocks__/api/LedgerSync/challenge.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"json": {
"version": 0,
"challenge": {
"data": "f0c8ba737d490e16fb10dec07d2ae872",
"expiry": "2024-09-18T13:41:45Z"
},
"host": "trustchain-backend.api.aws.stg.ldg-tech.com",
"rp": [
{
"credential": {
"version": 0,
"curveId": 33,
"signAlgorithm": 1,
"publicKey": "03cb7628e7248ddf9c07da54b979f16bf081fb3d173aac0992ad2a44ef6a388ae2"
},
"signature": "3045022100fc6b314d0cfc74ccb3b3aa2ff0d5648c9b4e8ef997eae2370593f78223be0b1b02201e56255b3b3caf29a349ca8d69c0955b32f0eed54d70077d2b46f23b4fb19052"
}
],
"protocolVersion": {
"major": 1,
"minor": 0,
"patch": 0
}
},
"tlv": "0101070201001210f0c8ba737d490e16fb10dec07d2ae87214010115473045022100fc6b314d0cfc74ccb3b3aa2ff0d5648c9b4e8ef997eae2370593f78223be0b1b02201e56255b3b3caf29a349ca8d69c0955b32f0eed54d70077d2b46f23b4fb19052160466ead899202b7472757374636861696e2d6261636b656e642e6170692e6177732e7374672e6c64672d746563682e636f6d320121332103cb7628e7248ddf9c07da54b979f16bf081fb3d173aac0992ad2a44ef6a388ae2600401000000"
}
1 change: 1 addition & 0 deletions apps/ledger-live-mobile/__mocks__/api/LedgerSync/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "name": "cloud-sync-backend-service", "version": "0.5.1-RC2" }
4 changes: 4 additions & 0 deletions apps/ledger-live-mobile/__mocks__/api/LedgerSync/v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"m/": "01010102201415fb105d3e3cf464bcb7cce33380c480941659f7898948d35a5baf6c29b2930621032696ebd7c276cb208382cca96388abc5f150d415b599f7983ff3575bce44140101010110b005000102000006210306e3967662753cee32f227206f75327f0cc8fe0ca946ffd3f506fc4177b67fbe05100991dfda0c5bccdef61c983b284d4d0105508e4a84ab9ddedca1e31f3a7ee15f01666dd6e25f029527bc7901956aea2938a187cdfcf105932be5f8839d4722fd7e5bcde14afdd48622c9ce1d7049d48f8d6e23e352d05ace6494ec5e4090b0680807062102a9ae8ecdae5e00ff5a5f825c69d2994ce6f8833137f5df30eb8022db4f0ac2170346304402206c05e3366d190556062cc64a5cdcd294aa79e81259a1d82676d94dfe402243b4022043c6fede859beb41e0847905869b9ac4bc4050f25f507cf6324da360f24eb682",
"m/16'": "01010102200c9ec1a1ab774f7eaeff2b0d4ad695f1fa07ea28d33f5d34126cb1152d6d83f60621032696ebd7c276cb208382cca96388abc5f150d415b599f7983ff3575bce44140101010315b8050c800000008000001080000000062103183c0c8122c89dd59204919d434f08abf831e743fd826e4ce9bbdb9cad49d6710510b27a7045d2537beb7093c0f96459d9150550b356f67f576caaf6c57bec42cfff397a3ab970844fa380f0b186129155dd3973fa3ab445201dc7e0a5537e7ae3b175594dc6db58b34ef9b5162cfbdd78b4d72ea46189532bc4889ef46a35131467c5b8062103f1041567f9b8b0f658388e2d7f033239e2884c109fa4c1a751e7ae2e3d640e181137040c64656275672d643638326230062103d682b0be923a68e2aa077c3b49c79be57d447d8dca615628f5adceb2ccd175be0104ffffffff12aa0510b5fb0ca72e5c79d5b2229eba894ee85d05505807e4e403453725031e892885aba11acec0ea1f814b013a0e4841e24ab07cd4c1c9dc9c2829c992d3a0ae416a7db24e9b96cc73c2454c8b5849aaa3db2c80afa395bab59957e6b17d7fdbd5ec124476062103d682b0be923a68e2aa077c3b49c79be57d447d8dca615628f5adceb2ccd175be0621020918680272a96341dadeb69e43800618c739f150c066162065ff351d4298de3a0346304402202ffa1cb831595fe2594fd45c094987b32b49934bef9f285ff6086997a3ab46b3022043ba33239b19a0323788d29c2c638d4408097f144194219cc813ae4e31a476d6"
}
5 changes: 4 additions & 1 deletion apps/ledger-live-mobile/__tests__/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import marketHandlers from "./market";
import ledgerSyncHandlers from "./ledgerSync";

export const ALLOWED_UNHANDLED_REQUESTS = [
"ledger.statuspage.io",
"cdn.live.ledger.com/announcements",
"swap.ledger.com/v5/currencies/all",
"https://cdn.live.ledger.com/swap-providers/data.json",
"https://crypto-assets-service.api.ledger.com/v1/partners?output=name,signature,public_key,public_key_curve&service_name=swap",
];

export default [...marketHandlers];
export default [...marketHandlers, ...ledgerSyncHandlers];
27 changes: 27 additions & 0 deletions apps/ledger-live-mobile/__tests__/handlers/ledgerSync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { http, HttpResponse } from "msw";
import AuthenticateJson from "../../__mocks__/api/LedgerSync/authenticate.json";
import ChallengeJson from "../../__mocks__/api/LedgerSync/challenge.json";
import InfoJson from "../../__mocks__/api/LedgerSync/info.json";
import v1Json from "../../__mocks__/api/LedgerSync/v1.json";
const handlers = [
http.post("https://trustchain-backend.api.aws.stg.ldg-tech.com/v1/authenticate", () => {
return HttpResponse.json(AuthenticateJson);
}),
http.get("https://trustchain-backend.api.aws.stg.ldg-tech.com/v1/challenge", () => {
return HttpResponse.json(ChallengeJson);
}),
http.get("https://cloud-sync-backend.api.aws.stg.ldg-tech.com/_info", () => {
return HttpResponse.json(InfoJson);
}),
http.get("https://trustchain-backend.api.aws.stg.ldg-tech.com/_info", () => {
return HttpResponse.json(InfoJson);
}),
http.get(
"https://trustchain-backend.api.aws.stg.ldg-tech.com/v1/trustchain/000c9ec1a1ab774f7eaeff2b0d4ad695f1fa07ea28d33f5d34126cb1152d6d83f6",
() => {
return HttpResponse.json(v1Json);
},
),
];

export default handlers;
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { screen } from "@testing-library/react-native";
import { render } from "@tests/test-renderer";
import { WalletSyncSettingsNavigator } from "./shared";
import { State } from "~/reducers/types";
import { crypto } from "@ledgerhq/hw-trustchain";

jest.mock("../hooks/useDestroyTrustchain", () => ({
useDestroyTrustchain: () => ({
Expand All @@ -16,6 +17,7 @@ jest.mock("../hooks/useDestroyTrustchain", () => ({

describe("ManageKey", () => {
it("Should open ManageKey flow and delete trustchain", async () => {
const keypair = await crypto.randomKeypair();
const { user } = render(<WalletSyncSettingsNavigator />, {
overrideInitialState: (state: State) => ({
...state,
Expand All @@ -39,13 +41,13 @@ describe("ManageKey", () => {
trustchain: {
...state.trustchain,
trustchain: {
rootId: "rootId",
applicationPath: "applicationPath",
walletSyncEncryptionKey: "walletSyncEncryptionKey",
rootId: "000c9ec1a1ab774f7eaeff2b0d4ad695f1fa07ea28d33f5d34126cb1152d6d83f6",
applicationPath: "m/0'/16'/0'",
walletSyncEncryptionKey: crypto.to_hex(keypair.privateKey),
},
memberCredentials: {
privatekey: "privatekey",
pubkey: "pubkey",
privatekey: crypto.to_hex(keypair.privateKey),
pubkey: "03d682b0be923a68e2aa077c3b49c79be57d447d8dca615628f5adceb2ccd175be",
},
},
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ import { screen } from "@testing-library/react-native";
import { render } from "@tests/test-renderer";
import { WalletSyncSettingsNavigator } from "./shared";
import { State } from "~/reducers/types";
import { crypto } from "@ledgerhq/hw-trustchain";

describe("WalletSyncActivated", () => {
it("Should open WalletSyncActivated screen", async () => {
const keypair = await crypto.randomKeypair();

const { user } = render(<WalletSyncSettingsNavigator />, {
overrideInitialState: (state: State) => ({
...state,
Expand All @@ -28,9 +32,13 @@ describe("WalletSyncActivated", () => {
trustchain: {
...state.trustchain,
trustchain: {
rootId: "rootId",
applicationPath: "applicationPath",
walletSyncEncryptionKey: "walletSyncEncryptionKey",
rootId: "000c9ec1a1ab774f7eaeff2b0d4ad695f1fa07ea28d33f5d34126cb1152d6d83f6",
applicationPath: "m/0'/16'/0'",
walletSyncEncryptionKey: crypto.to_hex(keypair.privateKey),
},
memberCredentials: {
privatekey: crypto.to_hex(keypair.privateKey),
pubkey: "03d682b0be923a68e2aa077c3b49c79be57d447d8dca615628f5adceb2ccd175be",
},
},
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { screen } from "@testing-library/react-native";
import { render } from "@tests/test-renderer";
import { WalletSyncSettingsNavigator } from "./shared";
import { State } from "~/reducers/types";
import { http, HttpResponse } from "msw";
import { server } from "@tests/server";

jest.mock("../hooks/useLedgerSyncStatus", () => ({
useLedgerSyncStatus: () => ({
Expand Down Expand Up @@ -44,6 +46,12 @@ describe("WalletSyncStatus", () => {
}),
});

server.use(
http.get("https://trustchain-backend.api.aws.stg.ldg-tech.com/v1/challenge", () => {
return HttpResponse.error();
}),
);

// Check if the ledger sync row is visible
await expect(await screen.findByText(/ledger sync/i)).toBeVisible();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useEffect, useState } from "react";

export function useCustomTimeOut(timeout: number) {
const [isTimeout, setIsTimeout] = useState(false);

useEffect(() => {
const timer = setTimeout(() => {
setIsTimeout(true);
}, timeout);

return () => {
clearTimeout(timer);
};
}, [timeout]);

return isTimeout;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ export const useLifeCycle = () => {
};

function handleError(error: Error) {
console.error("GetMember :" + error);

if (error instanceof TrustchainEjected) reset();
if (error instanceof TrustchainNotAllowed) reset();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { TrackScreen } from "~/analytics";
import { AlertLedgerSyncDown } from "../../components/AlertLedgerSyncDown";
import { useLedgerSyncStatus } from "../../hooks/useLedgerSyncStatus";
import { TrustchainNotFound } from "@ledgerhq/trustchain/errors";
import { useCustomTimeOut } from "../../hooks/useCustomTimeOut";

const WalletSyncManage = () => {
const { t } = useTranslation();
Expand All @@ -29,7 +30,15 @@ const WalletSyncManage = () => {

const { error: ledgerSyncError, isError: isLedgerSyncError } = useLedgerSyncStatus();

const { data, isLoading, isError, error: manageInstancesError } = manageInstancesHook.memberHook;
const {
data,
isLoading,
isError,
error: manageInstancesError,
isFetching,
isFetchedAfterMount,
isPending,
} = manageInstancesHook.memberHook;

const { onClickTrack } = useLedgerSyncAnalytics();

Expand Down Expand Up @@ -97,62 +106,76 @@ const WalletSyncManage = () => {

const hasError = isLedgerSyncError || isError;

const queryFetching = isPending || isFetching;
// the following checks if the instance has been deleted from another device to avoid a blink
// in dev on a real device it will blink since it's laggy
const unsynchronizedInstance = !data && !isFetchedAfterMount;

const forcedTimeLoaderOver = useCustomTimeOut(500);
const shouldDisplayLoader = !forcedTimeLoaderOver || unsynchronizedInstance || queryFetching;

return (
<Box height="100%" paddingX="16px">
<TrackScreen category={AnalyticsPage.LedgerSyncSettings} />

{getTopContent()}

{Options.map((props, index) => (
<Option
{...props}
key={index}
disabled={
props.id === "manageKey"
? hasError && error instanceof TrustchainNotFound
? false
: hasError
: hasError
}
/>
))}

<InstancesRow disabled={hasError} onPress={isError ? undefined : goToManageInstances}>
<Container
flexDirection="row"
justifyContent="space-between"
paddingTop={24}
alignItems="center"
disabled={hasError}
>
{isLoading ? (
<InfiniteLoader size={16} />
) : (
<Text fontWeight="semiBold" variant="large" color="neutral.c100">
{isError
? t("walletSync.walletSyncActivated.synchronizedInstances.error")
: t("walletSync.walletSyncActivated.synchronizedInstances.title", {
count: data?.length,
})}
</Text>
)}

<Flex flexDirection="row" alignItems="center" justifyContent="center">
<Text variant="body" color="primary.c80" mr={2}>
{t("walletSync.walletSyncActivated.synchronizedInstances.cta")}
</Text>
<Icons.ChevronRight size="M" color="neutral.c70" />
</Flex>
</Container>
</InstancesRow>

<ActivationDrawer
startingStep={Steps.ChooseSyncMethod}
isOpen={isSyncDrawerOpen}
handleClose={closeSyncDrawer}
/>
<ManageKeyDrawer {...manageKeyHook} />
<ManageInstanceDrawer {...manageInstancesHook} />
{shouldDisplayLoader ? (
<Flex justifyContent="center" alignItems="center" height="100%">
<InfiniteLoader size={64} />
</Flex>
) : (
<>
{getTopContent()}
{Options.map((props, index) => (
<Option
{...props}
key={index}
disabled={
props.id === "manageKey"
? hasError && error instanceof TrustchainNotFound
? false
: hasError
: hasError
}
/>
))}

<InstancesRow disabled={hasError} onPress={isError ? undefined : goToManageInstances}>
<Container
flexDirection="row"
justifyContent="space-between"
paddingTop={24}
alignItems="center"
disabled={hasError}
>
{isLoading ? (
<InfiniteLoader size={16} />
) : (
<Text fontWeight="semiBold" variant="large" color="neutral.c100">
{isError
? t("walletSync.walletSyncActivated.synchronizedInstances.error")
: t("walletSync.walletSyncActivated.synchronizedInstances.title", {
count: data?.length,
})}
</Text>
)}

<Flex flexDirection="row" alignItems="center" justifyContent="center">
<Text variant="body" color="primary.c80" mr={2}>
{t("walletSync.walletSyncActivated.synchronizedInstances.cta")}
</Text>
<Icons.ChevronRight size="M" color="neutral.c70" />
</Flex>
</Container>
</InstancesRow>

<ActivationDrawer
startingStep={Steps.ChooseSyncMethod}
isOpen={isSyncDrawerOpen}
handleClose={closeSyncDrawer}
/>
<ManageKeyDrawer {...manageKeyHook} />
<ManageInstanceDrawer {...manageInstancesHook} />
</>
)}
</Box>
);
};
Expand Down

0 comments on commit d9a4644

Please sign in to comment.