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

add/connect wallet flow #4239

Merged
merged 9 commits into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
updates
  • Loading branch information
peterpme committed Jun 27, 2023
commit ec169e3ddbf26591d88b48fd94e03f09b0b7067b
6 changes: 6 additions & 0 deletions packages/app-mobile/src/Images.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
const Images = {
solanaLogo: require("../assets/blockchains/solana.png"),
ethereumLogo: require("../assets/blockchains/ethereum.png"),
logoAvalanche: require("./images/logo-avalanche.png"),
logoBsc: require("./images/logo-bsc.png"),
logoCosmos: require("./images/logo-cosmos.png"),
logoEthereum: require("./images/logo-ethereum.png"),
logoPolygon: require("./images/logo-polygon.png"),
logoSolana: require("./images/logo-solana.png"),
};

export default Images;
9 changes: 7 additions & 2 deletions packages/app-mobile/src/components/MnemonicInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from "react";
import { Alert, Pressable, View, Text } from "react-native";
import { Alert, Pressable } from "react-native";

import {
UI_RPC_METHOD_KEYRING_STORE_MNEMONIC_CREATE,
Expand Down Expand Up @@ -59,8 +59,13 @@ export function MnemonicInput({ readOnly, onComplete }: MnemonicInputProps) {

const onChange = async (words: string[]) => {
setMnemonicWords(words);
if (words.length > 11) {
if (readOnly) {
const mnemonic = mnemonicWords.map((f) => f.trim()).join(" ");
onComplete({ isValid: true, mnemonic });
return;
}

if (words.length > 11) {
const isValid = words.length > 11 ? await isValidAsync(mnemonic) : false;
onComplete({ isValid, mnemonic });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import {
AddWalletSelectBlockchain,
AddWalletCreateOrImportScreen,
AddWalletAdvancedImportScreen,
ImportFromMnemonicScreen,
} from "~screens/Unlocked/Settings/AddConnectWalletScreen";
import { ChangePasswordScreen } from "~screens/Unlocked/Settings/ChangePasswordScreen";
import { PreferencesScreen } from "~screens/Unlocked/Settings/PreferencesScreen";
Expand Down Expand Up @@ -351,6 +352,11 @@ export function AccountSettingsNavigator(): JSX.Element {
name="AddWalletAdvancedImport"
component={AddWalletAdvancedImportScreen}
/>
<Stack.Screen
options={{ title: "Recovery Phrase" }}
name="ImportFromMnemonic"
component={ImportFromMnemonicScreen}
/>
</Stack.Group>
<Stack.Group
screenOptions={{ presentation: "modal", headerShown: false }}
Expand Down
18 changes: 8 additions & 10 deletions packages/app-mobile/src/navigation/OnboardingNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import {
View,
Platform,
KeyboardAvoidingView,
Pressable,
Text,
DevSettings,
StyleProp,
ViewStyle,
Expand All @@ -33,8 +31,6 @@ import {
DISCORD_INVITE_LINK,
toTitleCase,
TWITTER_LINK,
UI_RPC_METHOD_KEYRING_STORE_MNEMONIC_CREATE,
UI_RPC_METHOD_KEYRING_VALIDATE_MNEMONIC,
XNFT_GG_LINK,
PrivateKeyWalletDescriptor,
} from "@coral-xyz/common";
Expand Down Expand Up @@ -78,16 +74,13 @@ import {
FullScreenLoading,
Header,
Margin,
MnemonicInputFields,
PrimaryButton,
SecondaryButton,
LinkButton,
Screen,
StyledText,
SubtextParagraph,
WelcomeLogoHeader,
CopyButton,
PasteButton,
EmptyState,
CallToAction,
} from "~components/index";
Expand Down Expand Up @@ -661,8 +654,6 @@ function OnboardingMnemonicInputScreen({
const { action } = onboardingData;
const readOnly = action === "create";

const isButtonEnabled = readOnly ? checked : isValid;

const subtitle = readOnly
? "This is the only way to recover your account if you lose your device. Write it down and store it in a safe place."
: "Enter your 12 or 24-word secret recovery mnemonic to add an existing wallet.";
Expand All @@ -680,6 +671,9 @@ function OnboardingMnemonicInputScreen({
}
};

const isButtonDisabled =
(readOnly && !checked) || (!readOnly && !isValid && !checked);

return (
<OnboardingScreen title="Secret recovery phrase" subtitle={subtitle}>
<YStack f={1}>
Expand All @@ -694,6 +688,7 @@ function OnboardingMnemonicInputScreen({
value={checked}
onPress={() => {
setChecked(!checked);
setIsValid(readOnly && !checked);
}}
/>
</Margin>
Expand All @@ -702,8 +697,11 @@ function OnboardingMnemonicInputScreen({
{maybeRender(Boolean(error), () => (
<ErrorMessage for={{ message: error }} />
))}
<StyledText>
{JSON.stringify({ isValid, checked, error, readOnly })}
</StyledText>
<PrimaryButton
disabled={!isButtonEnabled}
disabled={isButtonDisabled}
label={action === "create" ? "Next" : "Import"}
onPress={() => {
if (isValid) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { WalletListItem } from "~screens/Unlocked/EditWalletsScreen";
import { SettingsList } from "./components/SettingsMenuList";
import { IconPushDetail } from "./components/SettingsRow";

import { MnemonicInput } from "~src/components/MnemonicInput";
import { useSession } from "~src/lib/SessionProvider";

export function AddWalletPrivacyDisclaimer({ navigation }): JSX.Element {
Expand Down Expand Up @@ -280,3 +281,51 @@ export function AddWalletAdvancedImportScreen({ navigation, route }) {
</Screen>
);
}

export function ImportFromMnemonicScreen({ navigation, route }): JSX.Element {
const insets = useSafeAreaInsets();
const { blockchain, keyringExists, inputMnemonic } = route.params;
const [isValid, setIsValid] = useState(false);

const onComplete = ({
isValid,
mnemonic,
}: {
isValid: boolean;
mnemonic: string;
}) => {
setIsValid(isValid);
if (isValid) {
console.log(mnemonic);
}
};

return (
<Screen jc="space-between" style={{ marginBottom: insets.bottom }}>
<YStack f={1}>
<YStack mb={24}>
<Header text="Secret Recovery Phrase" />
<SubtextParagraph>
Enter your 12 or 24-word secret recovery mnemonic to add an existing
wallet.
</SubtextParagraph>
</YStack>
<MnemonicInput readOnly={!inputMnemonic} onComplete={onComplete} />
</YStack>

<PrimaryButton
disabled={!isValid}
label="Next"
onPress={() => {
// if (isValid) {
// const route =
// action === "recover" ? "MnemonicSearch" : "SelectBlockchain";
// navigation.push(route);
// } else {
// setError("Invalid secret recovery phrase");
// }
}}
/>
</Screen>
);
}
38 changes: 25 additions & 13 deletions packages/tamagui-core/src/components/Images.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Image } from "tamagui";

import Images from "~src/Images";

export function S3Image({
resource,
style,
Expand All @@ -13,13 +15,17 @@ export function S3Image({
}): JSX.Element {
// TODO update this to CNAME properly for your bucket
const baseUrl = "https://dphpu5y2e06qu.cloudfront.net";
const url = `${baseUrl}/${resource}`;
const url = `${baseUrl}/images/${resource}`;
return (
// @ts-ignore
<Image src={url} width={style.width} height={style.height} {...props} />
);
}

function LocalImage({ resource, style }): JSX.Element {
return <Image source={resource} width={style.width} height={style.height} />;
}

type BlockchainLogoProps = {
width: number;
height: number;
Expand All @@ -29,8 +35,9 @@ export const EthereumIcon = ({
width,
height,
}: BlockchainLogoProps): JSX.Element => (
<S3Image
resource="images/logo-ethereum.png"
<LocalImage
resource={Images.logoEthereum}
// resource="logo-ethereum.png"
style={{
width,
height,
Expand All @@ -42,8 +49,9 @@ export const SolanaIcon = ({
width,
height,
}: BlockchainLogoProps): JSX.Element => (
<S3Image
resource="images/logo-solana.png"
<LocalImage
resource={Images.logoSolana}
// resource="logo-solana.png"
style={{
width,
height,
Expand All @@ -55,8 +63,9 @@ export const AvalancheIcon = ({
width,
height,
}: BlockchainLogoProps): JSX.Element => (
<S3Image
resource="images/logo-avalanche.png"
<LocalImage
resource={Images.logoAvalanche}
// resource="logo-avalanche.png"
style={{
width,
height,
Expand All @@ -68,8 +77,9 @@ export const PolygonIcon = ({
width,
height,
}: BlockchainLogoProps): JSX.Element => (
<S3Image
resource="images/logo-polygon.png"
<LocalImage
resource={Images.logoPolygon}
// resource="logo-polygon.png"
style={{
width,
height,
Expand All @@ -81,8 +91,9 @@ export const BscIcon = ({
width,
height,
}: BlockchainLogoProps): JSX.Element => (
<S3Image
resource="images/logo-bsc.png"
<LocalImage
resource={Images.logoBsc}
// resource="logo-bsc.png"
style={{
width,
height,
Expand All @@ -94,8 +105,9 @@ export const CosmosIcon = ({
width,
height,
}: BlockchainLogoProps): JSX.Element => (
<S3Image
resource="images/logo-cosmos.png"
<LocalImage
resource={Images.logoCosmos}
// resource="logo-cosmos.png"
style={{
width,
height,
Expand Down