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

Show wallet creation error when key length mismatched #436

16 changes: 16 additions & 0 deletions assets/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
"message": "Close",
"description": "Close button text"
},
"retry": {
"message": "Retry",
"description": "Retry button text"
},
"add_wallet": {
"message": "Add wallet",
"description": "Add a wallet text"
Expand Down Expand Up @@ -677,6 +681,18 @@
"message": "The key length of the wallet you are importing is less than the required length to transact on the AO network. It is recommended you create a new ArConnect wallet and transfer your assets to your new wallet.",
"description": "Key Length Too Short error"
},
"generate_wallet_key_length_short_error_title": {
"message": "Error generating wallet",
"description": "Key Length Too Short error title"
},
"generate_wallet_key_length_short_error": {
"message": "Click the retry button below to try again.",
"description": "Key Length Too Short error"
},
"generate_wallet_in_progress": {
"message": "The wallet creation process can take 30-60 seconds.",
"description": "Generate wallet in progresss text"
},
"development_version": {
"message": "Development",
"description": "Development version badge text"
Expand Down
16 changes: 16 additions & 0 deletions assets/_locales/zh_CN/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
"message": "关闭",
"description": "Close button text"
},
"retry": {
"message": "重试",
"description": "Retry button text"
},
"add_wallet": {
"message": "添加钱包",
"description": "Add a wallet text"
Expand Down Expand Up @@ -677,6 +681,18 @@
"message": "您导入的钱包的密钥长度小于在 AO 网络上进行交易所需的长度。建议您创建一个新的ArConnect钱包,并将您的资产转移到新钱包中。",
"description": "Key Length Too Short error"
},
"generate_wallet_key_length_short_error_title": {
"message": "生成钱包时出错",
"description": "Key Length Too Short error title"
},
"generate_wallet_key_length_short_error": {
"message": "单击下面的重试按钮再试一次。",
"description": "Key Length Too Short error"
},
"generate_wallet_in_progress": {
"message": "钱包创建过程可能需要 30-60 秒。",
"description": "Generate wallet in progresss text"
},
"development_version": {
"message": "开发版本",
"description": "Development version badge text"
Expand Down
17 changes: 16 additions & 1 deletion src/components/dashboard/subsettings/AddWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import Arweave from "arweave/web/common";
import styled from "styled-components";
import { defaultGateway } from "~gateways/gateway";
import { WalletKeySizeErrorModal } from "~components/modals/WalletKeySizeErrorModal";
import { WalletRetryCreationModal } from "~components/modals/WalletRetryCreationModal";

export default function AddWallet() {
// password input
Expand All @@ -31,6 +32,9 @@ export default function AddWallet() {
// wallet size error modal
const walletModal = useModal();

// wallet retry modal
const walletRetryModal = useModal();

// toasts
const { setToast } = useToasts();

Expand Down Expand Up @@ -184,7 +188,7 @@ export default function AddWallet() {
}, []);

// generate new wallet
async function generateWallet() {
async function generateWallet(retry?: boolean) {
setGenerating(true);

// generate a seedphrase
Expand Down Expand Up @@ -239,6 +243,13 @@ export default function AddWallet() {
}

try {
const { actualLength, expectedLength } = await getWalletKeyLength(
generatedWallet.jwk
);
if (actualLength !== expectedLength) {
walletRetryModal.setOpen(true);
return;
}
// add the wallet
await addWallet(generatedWallet.jwk, passwordInput.state);

Expand Down Expand Up @@ -339,6 +350,10 @@ export default function AddWallet() {
</ButtonV2>
</div>
<WalletKeySizeErrorModal {...walletModal} />
<WalletRetryCreationModal
{...walletRetryModal}
onRetry={generateWallet}
/>
</Wrapper>
);
}
Expand Down
85 changes: 85 additions & 0 deletions src/components/modals/WalletRetryCreationModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { ButtonV2, ModalV2, Spacer } from "@arconnect/components";
import { useRef, useState } from "react";
import browser from "webextension-polyfill";
import { ContentWrapper, Content, HeaderText, CenterText } from "./Components";
import styled from "styled-components";
import type { JWKInterface } from "arweave/web/lib/wallet";
import { getWalletKeyLength } from "~wallets";

interface Props {
isOpen: boolean;
setOpen: (value: boolean) => void;
onRetry: (
retry?: boolean
) => Promise<Partial<{ seedphrase: string; jwk: JWKInterface }>>;
}

export const WalletRetryCreationModal = ({
isOpen,
setOpen,
onRetry
}: Props) => {
const modalRef = useRef(null);
const [loading, setLoading] = useState(false);

async function handleRetry() {
if (loading) return;
setLoading(true);
try {
const { jwk } = await onRetry(true);
const { actualLength, expectedLength } = await getWalletKeyLength(jwk);
if (actualLength === expectedLength) {
setOpen(false);
}
} catch {}
setLoading(false);
}

return (
<ModalV2
root={document.getElementById("__plasmo")}
open={isOpen}
setOpen={setOpen}
actions={<></>}
>
<ContentWrapper ref={modalRef}>
<Content>
<div>
<HeaderText noMargin heading>
{browser.i18n.getMessage(
"generate_wallet_key_length_short_error_title"
)}
</HeaderText>
<Spacer y={1} />
<CenterText>
{browser.i18n.getMessage(
"generate_wallet_key_length_short_error"
)}
</CenterText>
<Spacer y={1} />
</div>
</Content>
<ButtonsWrapper>
<ButtonV2 fullWidth onClick={handleRetry} loading={loading}>
{browser.i18n.getMessage("retry")}
</ButtonV2>
<ButtonV2 fullWidth secondary onClick={() => setOpen(false)}>
{browser.i18n.getMessage("cancel")}
</ButtonV2>
</ButtonsWrapper>
<Spacer y={0.5} />
{loading && (
<CenterText>
{browser.i18n.getMessage("generate_wallet_in_progress")}
</CenterText>
)}
</ContentWrapper>
</ModalV2>
);
};

const ButtonsWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 8px;
`;
2 changes: 1 addition & 1 deletion src/routes/popup/passwordPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import aoLogo from "url:/assets/ecosystem/ao-token-logo.png";
import styled from "styled-components";
import { CheckIcon, CloseIcon } from "@iconicicons/react";
import { ResetButton } from "~components/dashboard/Reset";
import { Content, ContentWrapper } from "./announcement";
import { Content, ContentWrapper } from "~components/modals/Components";

export const PasswordWarningModal = ({
open,
Expand Down
61 changes: 52 additions & 9 deletions src/routes/welcome/generate/backup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ButtonV2, Spacer, Text } from "@arconnect/components";
import { ButtonV2, Spacer, Text, useModal } from "@arconnect/components";
import { useLocation, useRoute } from "wouter";
import { useContext, useEffect, useState } from "react";
import { useContext, useEffect, useRef, useState } from "react";
import { WalletContext } from "../setup";
import Paragraph from "~components/Paragraph";
import browser from "webextension-polyfill";
Expand All @@ -14,13 +14,24 @@ import {
EyeOffIcon
} from "@iconicicons/react";
import { PageType, trackPage } from "~utils/analytics";
import { getWalletKeyLength } from "~wallets";
import { WalletRetryCreationModal } from "~components/modals/WalletRetryCreationModal";

export default function Backup() {
// seed blur status
const [shown, setShown] = useState(false);

// loading
const [loading, setLoading] = useState(false);

// wallet retry modal
const walletRetryModal = useModal();

// wallet context
const generatedWallet = useContext(WalletContext);
const { wallet: generatedWallet, generateWallet } = useContext(WalletContext);

// ref to track the latest generated wallet
const walletRef = useRef(generatedWallet);

// route
const [, params] = useRoute<{ setup: string; page: string }>("/:setup/:page");
Expand All @@ -36,6 +47,39 @@ export default function Backup() {
setTimeout(() => setCopyDisplay(true), 1050);
}

async function handleNext() {
if (loading) return;
setLoading(true);

try {
if (!walletRef.current.jwk) {
await new Promise((resolve) => {
const checkState = setInterval(() => {
if (walletRef.current.jwk) {
clearInterval(checkState);
resolve(null);
}
}, 500);
});
}

const { actualLength, expectedLength } = await getWalletKeyLength(
walletRef.current.jwk
);
if (expectedLength !== actualLength) {
walletRetryModal.setOpen(true);
} else {
setLocation(`/${params.setup}/${Number(params.page) + 1}`);
}
} catch {}

setLoading(false);
}

useEffect(() => {
walletRef.current = generatedWallet;
}, [generatedWallet]);

// Segment
useEffect(() => {
trackPage(PageType.ONBOARD_BACKUP);
Expand All @@ -55,15 +99,14 @@ export default function Backup() {
{browser.i18n.getMessage("copySeed")}
</CopySeed>
<Spacer y={1} />
<ButtonV2
fullWidth
onClick={() =>
setLocation(`/${params.setup}/${Number(params.page) + 1}`)
}
>
<ButtonV2 fullWidth onClick={handleNext} loading={loading}>
{browser.i18n.getMessage("next")}
<ArrowRightIcon />
</ButtonV2>
<WalletRetryCreationModal
{...walletRetryModal}
onRetry={generateWallet}
/>
</>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/routes/welcome/generate/confirm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { PageType, trackPage } from "~utils/analytics";

export default function Confirm() {
// wallet context
const generatedWallet = useContext(WalletContext);
const { wallet: generatedWallet } = useContext(WalletContext);

// toasts
const { setToast } = useToasts();
Expand Down
2 changes: 1 addition & 1 deletion src/routes/welcome/generate/done.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { addExpiration } from "~wallets/auth";

export default function Done() {
// wallet context
const wallet = useContext(WalletContext);
const { wallet } = useContext(WalletContext);

const [, setLocation] = useLocation();

Expand Down
12 changes: 4 additions & 8 deletions src/routes/welcome/load/password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,12 @@ export default function Password() {
setLocation(`/${params.setup}/${Number(params.page) + 1}`);
}

// password valid
const validPassword = useMemo(
() => checkPasswordValid(passwordInput.state),
[passwordInput]
);

// passwords match
const matches = useMemo(
() => passwordInput.state === validPasswordInput.state && validPassword,
[passwordInput, validPasswordInput, validPassword]
() =>
passwordInput.state === validPasswordInput.state &&
passwordInput.state?.length >= 5,
[passwordInput, validPasswordInput]
);

// Segment
Expand Down
Loading