diff --git a/.changeset/real-apricots-rush.md b/.changeset/real-apricots-rush.md
new file mode 100644
index 000000000000..0d9dd54104c4
--- /dev/null
+++ b/.changeset/real-apricots-rush.md
@@ -0,0 +1,5 @@
+---
+"live-mobile": patch
+---
+
+Trustchain integration on LLM scan qr code. We can now join a trustchain scanning a qr code
diff --git a/apps/ledger-live-mobile/src/newArch/features/Accounts/screens/AddAccount/components/StepFlow.tsx b/apps/ledger-live-mobile/src/newArch/features/Accounts/screens/AddAccount/components/StepFlow.tsx
index 149fba5c38ef..aff96d6ad81c 100644
--- a/apps/ledger-live-mobile/src/newArch/features/Accounts/screens/AddAccount/components/StepFlow.tsx
+++ b/apps/ledger-live-mobile/src/newArch/features/Accounts/screens/AddAccount/components/StepFlow.tsx
@@ -2,13 +2,15 @@ import React from "react";
import SelectAddAccountMethod from "./SelectAddAccountMethod";
import ChooseSyncMethod from "LLM/features/WalletSync/screens/Synchronize/ChooseMethod";
import QrCodeMethod from "LLM/features/WalletSync/screens/Synchronize/QrCodeMethod";
-import PinCodeInput from "LLM/features/WalletSync/screens/Synchronize/PinCodeInput";
import { TrackScreen } from "~/analytics";
import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets";
import { AnalyticsPage } from "LLM/features/WalletSync/hooks/useLedgerSyncAnalytics";
import { Options, Steps } from "LLM/features/WalletSync/types/Activation";
import SyncError from "LLM/features/WalletSync/screens/Synchronize/SyncError";
import PinCodeDisplay from "LLM/features/WalletSync/screens/Synchronize/PinCodeDisplay";
+import PinCodeInput from "LLM/features/WalletSync/screens/Synchronize/PinCodeInput";
+import { useInitMemberCredentials } from "~/newArch/features/WalletSync/hooks/useInitMemberCredentials";
+import { useSyncWithQrCode } from "~/newArch/features/WalletSync/hooks/useSyncWithQrCode";
type Props = {
currentStep: Steps;
@@ -19,7 +21,7 @@ type Props = {
currentOption: Options;
navigateToChooseSyncMethod: () => void;
navigateToQrCodeMethod: () => void;
- onQrCodeScanned: (data: string) => void;
+ onQrCodeScanned: () => void;
qrProcess: {
url: string | null;
error: Error | null;
@@ -38,7 +40,21 @@ const StepFlow = ({
navigateToQrCodeMethod,
onQrCodeScanned,
qrProcess,
+ setCurrentStep,
}: Props) => {
+ const { memberCredentials } = useInitMemberCredentials();
+
+ const { handleStart, handleSendDigits, inputCallback, digits } = useSyncWithQrCode();
+
+ const handleQrCodeScanned = (data: string) => {
+ onQrCodeScanned();
+ if (memberCredentials) handleStart(data, memberCredentials, setCurrentStep);
+ };
+
+ const handlePinCodeSubmit = (input: string) => {
+ if (input && inputCallback && digits === input.length) handleSendDigits(inputCallback, input);
+ };
+
const getScene = () => {
switch (currentStep) {
case Steps.AddAccountMethod:
@@ -62,7 +78,7 @@ const StepFlow = ({
case Steps.QrCodeMethod:
return (
@@ -72,7 +88,7 @@ const StepFlow = ({
return qrProcess.pinCode ? : null;
case Steps.PinInput:
- return ;
+ return ;
case Steps.SyncError:
return ;
diff --git a/apps/ledger-live-mobile/src/newArch/features/Accounts/screens/AddAccount/useAddAccountViewModel.ts b/apps/ledger-live-mobile/src/newArch/features/Accounts/screens/AddAccount/useAddAccountViewModel.ts
index 06a6c49721fe..8e1673f00894 100644
--- a/apps/ledger-live-mobile/src/newArch/features/Accounts/screens/AddAccount/useAddAccountViewModel.ts
+++ b/apps/ledger-live-mobile/src/newArch/features/Accounts/screens/AddAccount/useAddAccountViewModel.ts
@@ -54,11 +54,7 @@ const useAddAccountViewModel = ({ isOpened, onClose }: AddAccountDrawerProps) =>
currentOption,
});
- const onQrCodeScanned = (data: string) => {
- // eslint-disable-next-line no-console
- console.log(data);
- //setCurrentStep(Steps.PinCodeInput);
- };
+ const onQrCodeScanned = () => setCurrentStep(Steps.PinInput);
return {
isAddAccountDrawerVisible: isOpened,
@@ -69,8 +65,8 @@ const useAddAccountViewModel = ({ isOpened, onClose }: AddAccountDrawerProps) =>
setCurrentOption,
currentOption,
setCurrentStep,
- onGoBack,
onQrCodeScanned,
+ onGoBack,
qrProcess: {
url,
error,
diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/components/Activation/ActivationFlow.tsx b/apps/ledger-live-mobile/src/newArch/features/WalletSync/components/Activation/ActivationFlow.tsx
index ff01fde20e7c..2cd1fd66f8d7 100644
--- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/components/Activation/ActivationFlow.tsx
+++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/components/Activation/ActivationFlow.tsx
@@ -8,6 +8,8 @@ import { AnalyticsPage } from "../../hooks/useLedgerSyncAnalytics";
import PinCodeDisplay from "../../screens/Synchronize/PinCodeDisplay";
import PinCodeInput from "../../screens/Synchronize/PinCodeInput";
import SyncError from "../../screens/Synchronize/SyncError";
+import { useInitMemberCredentials } from "../../hooks/useInitMemberCredentials";
+import { useSyncWithQrCode } from "../../hooks/useSyncWithQrCode";
type Props = {
currentStep: Steps;
@@ -19,9 +21,10 @@ type Props = {
isLoading: boolean;
pinCode: string | null;
};
- onQrCodeScanned: (data: string) => void;
+ onQrCodeScanned: () => void;
currentOption: Options;
setOption: (option: Options) => void;
+ setCurrentStep: (step: Steps) => void;
};
const ActivationFlow = ({
@@ -32,7 +35,21 @@ const ActivationFlow = ({
currentOption,
setOption,
onQrCodeScanned,
+ setCurrentStep,
}: Props) => {
+ const { memberCredentials } = useInitMemberCredentials();
+
+ const { handleStart, handleSendDigits, inputCallback, digits } = useSyncWithQrCode();
+
+ const handleQrCodeScanned = (data: string) => {
+ onQrCodeScanned();
+ if (memberCredentials) handleStart(data, memberCredentials, setCurrentStep);
+ };
+
+ const handlePinCodeSubmit = (input: string) => {
+ if (input && inputCallback && digits === input.length) handleSendDigits(inputCallback, input);
+ };
+
const getScene = () => {
switch (currentStep) {
case Steps.Activation:
@@ -52,7 +69,7 @@ const ActivationFlow = ({
case Steps.QrCodeMethod:
return (
@@ -62,7 +79,7 @@ const ActivationFlow = ({
return qrProcess.pinCode ? : null;
case Steps.PinInput:
- return ;
+ return ;
case Steps.SyncError:
return ;
diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useInstanceName.ts b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useInstanceName.ts
new file mode 100644
index 000000000000..a0100935a0f5
--- /dev/null
+++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useInstanceName.ts
@@ -0,0 +1,12 @@
+import { getEnv } from "@ledgerhq/live-env";
+import { Platform } from "react-native";
+
+const platformMap: Record = {
+ ios: "iOS",
+ android: "Android",
+};
+
+export function useInstanceName(): string {
+ const hash = getEnv("USER_ID").slice(0, 5);
+ return `${platformMap[Platform.OS] ?? Platform.OS} ${Platform.Version} ${hash ? " " + hash : ""}`;
+}
diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useSyncWithQrCode.ts b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useSyncWithQrCode.ts
new file mode 100644
index 000000000000..7c6579407269
--- /dev/null
+++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useSyncWithQrCode.ts
@@ -0,0 +1,75 @@
+import { useCallback, useState } from "react";
+import { MemberCredentials } from "@ledgerhq/trustchain/types";
+import { createQRCodeCandidateInstance } from "@ledgerhq/trustchain/qrcode/index";
+import { InvalidDigitsError } from "@ledgerhq/trustchain/errors";
+import { setTrustchain } from "@ledgerhq/trustchain/store";
+import { useDispatch } from "react-redux";
+import { useNavigation } from "@react-navigation/native";
+import { Steps } from "../types/Activation";
+import { NavigatorName, ScreenName } from "~/const";
+import { useInstanceName } from "./useInstanceName";
+
+export const useSyncWithQrCode = () => {
+ const [digits, setDigits] = useState(null);
+ const [input, setInput] = useState(null);
+ const instanceName = useInstanceName();
+
+ const navigation = useNavigation();
+
+ const [inputCallback, setInputCallback] = useState<((input: string) => void) | null>(null);
+ const dispatch = useDispatch();
+
+ const onRequestQRCodeInput = useCallback(
+ (config: { digits: number }, callback: (input: string) => void) => {
+ setDigits(config.digits);
+ setInputCallback(() => callback);
+ },
+ [],
+ );
+
+ const onSyncFinished = useCallback(() => {
+ setDigits(null);
+ setInput(null);
+ setInputCallback(null);
+ navigation.navigate(NavigatorName.WalletSync, {
+ screen: ScreenName.WalletSyncSuccess,
+ params: {
+ created: false,
+ },
+ });
+ }, [navigation]);
+
+ const handleStart = useCallback(
+ async (
+ url: string,
+ memberCredentials: MemberCredentials,
+ setCurrentStep: (step: Steps) => void,
+ ) => {
+ try {
+ const trustchain = await createQRCodeCandidateInstance({
+ memberCredentials,
+ scannedUrl: url,
+ memberName: instanceName,
+ onRequestQRCodeInput,
+ });
+ dispatch(setTrustchain(trustchain));
+ onSyncFinished();
+ return true;
+ } catch (e) {
+ if (e instanceof InvalidDigitsError) {
+ setCurrentStep(Steps.SyncError);
+ return;
+ }
+ throw e;
+ }
+ },
+ [instanceName, onRequestQRCodeInput, onSyncFinished, dispatch],
+ );
+
+ const handleSendDigits = useCallback(
+ (inputCallback: (_: string) => void, input: string) => (inputCallback(input), true),
+ [],
+ );
+
+ return { digits, input, handleStart, handleSendDigits, setInput, inputCallback };
+};
diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useTrustchainSdk.ts b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useTrustchainSdk.ts
index d395d019f7ac..5bbfa3f859c3 100644
--- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useTrustchainSdk.ts
+++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useTrustchainSdk.ts
@@ -1,16 +1,11 @@
import { useMemo } from "react";
import { getEnv } from "@ledgerhq/live-env";
import { getSdk } from "@ledgerhq/trustchain/index";
-import { Platform } from "react-native";
import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import { TrustchainSDK } from "@ledgerhq/trustchain/types";
import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams";
-
-const platformMap: Record = {
- ios: "iOS",
- android: "Android",
-};
+import { useInstanceName } from "./useInstanceName";
let sdkInstance: TrustchainSDK | null = null;
@@ -19,14 +14,14 @@ export function useTrustchainSdk() {
const environment = featureWalletSync?.params?.environment;
const { trustchainApiBaseUrl } = getWalletSyncEnvironmentParams(environment);
const isMockEnv = !!getEnv("MOCK");
+ const instanceName = useInstanceName();
const defaultContext = useMemo(() => {
const applicationId = 16;
- const hash = getEnv("USER_ID").slice(0, 5);
- const name = `${platformMap[Platform.OS] ?? Platform.OS} ${Platform.Version} ${hash ? " " + hash : ""}`;
+ const name = instanceName;
return { applicationId, name, apiBaseUrl: trustchainApiBaseUrl };
- }, [trustchainApiBaseUrl]);
+ }, [trustchainApiBaseUrl, instanceName]);
if (sdkInstance === null) {
sdkInstance = getSdk(isMockEnv, defaultContext, withDevice);
diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Activation/ActivationDrawer.tsx b/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Activation/ActivationDrawer.tsx
index 6bc0afbfc201..545e26869dbd 100644
--- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Activation/ActivationDrawer.tsx
+++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Activation/ActivationDrawer.tsx
@@ -29,6 +29,7 @@ function View({
qrProcess,
currentOption,
setCurrentOption,
+ setCurrentStep,
}: ViewProps) {
const CustomDrawerHeader = () => ;
@@ -51,6 +52,7 @@ function View({
currentOption={currentOption}
setOption={setCurrentOption}
onQrCodeScanned={onQrCodeScanned}
+ setCurrentStep={setCurrentStep}
/>
diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Activation/useActivationDrawerModel.ts b/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Activation/useActivationDrawerModel.ts
index e118245d5ed4..f5763a62b96e 100644
--- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Activation/useActivationDrawerModel.ts
+++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Activation/useActivationDrawerModel.ts
@@ -49,12 +49,7 @@ const useActivationDrawerModel = ({ isOpen, startingStep, handleClose }: Props)
setCurrentStep(Steps.QrCodeMethod);
};
- // That means the url as be stored in the store
- const onQrCodeScanned = (data: string) => {
- // eslint-disable-next-line no-console
- console.log(data);
- //setCurrentStep(Steps.PinCodeInput);
- };
+ const onQrCodeScanned = () => setCurrentStep(Steps.PinInput);
const resetStep = () => setCurrentStep(startingStep);
const resetOption = () => setCurrentOption(Options.SCAN);
@@ -86,6 +81,7 @@ const useActivationDrawerModel = ({ isOpen, startingStep, handleClose }: Props)
qrProcess: { url, error, isLoading, pinCode },
currentOption,
setCurrentOption,
+ setCurrentStep,
};
};
diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Synchronize/PinCodeInput.tsx b/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Synchronize/PinCodeInput.tsx
index 7f5ad7f9facc..008695e20373 100644
--- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Synchronize/PinCodeInput.tsx
+++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/Synchronize/PinCodeInput.tsx
@@ -1,4 +1,4 @@
-import React, { forwardRef, useImperativeHandle, useRef, useState } from "react";
+import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { Flex, Text } from "@ledgerhq/native-ui";
import styled from "styled-components/native";
@@ -6,11 +6,21 @@ import { AnalyticsPage } from "../../hooks/useLedgerSyncAnalytics";
import TrackScreen from "~/analytics/TrackScreen";
import { NativeSyntheticEvent, TextInput, TextInputKeyPressEventData } from "react-native";
-export default function PinCodeInput() {
+type Props = {
+ handleSendDigits: (input: string) => void;
+};
+
+export default function PinCodeInput({ handleSendDigits }: Props) {
const { t } = useTranslation();
const inputRefs = [useRef(null), useRef(null), useRef(null)];
const [digits, setDigits] = useState(["", "", ""]);
+ useEffect(() => {
+ if (digits.every(digit => digit)) {
+ handleSendDigits(digits.join(""));
+ }
+ }, [digits, handleSendDigits]);
+
const handleChange = (value: string, index: number) => {
const newDigits = [...digits];
newDigits[index] = value;