diff --git a/assets/_locales/en/messages.json b/assets/_locales/en/messages.json
index 257f87ea..a9614de1 100644
--- a/assets/_locales/en/messages.json
+++ b/assets/_locales/en/messages.json
@@ -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"
@@ -677,6 +681,10 @@
"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_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"
@@ -791,6 +799,10 @@
"message": "Generating wallet...",
"description": "Generating wallet in progress text"
},
+ "longer_than_usual": {
+ "message": "Please wait, this is taking longer than usual...",
+ "description": "Longer than usual text"
+ },
"keyfile": {
"message": "Keyfile",
"description": "Keyfile text"
diff --git a/assets/_locales/zh_CN/messages.json b/assets/_locales/zh_CN/messages.json
index 6bcb11a2..2caba310 100644
--- a/assets/_locales/zh_CN/messages.json
+++ b/assets/_locales/zh_CN/messages.json
@@ -53,6 +53,10 @@
"message": "关闭",
"description": "Close button text"
},
+ "retry": {
+ "message": "重试",
+ "description": "Retry button text"
+ },
"add_wallet": {
"message": "添加钱包",
"description": "Add a wallet text"
@@ -677,6 +681,10 @@
"message": "您导入的钱包的密钥长度小于在 AO 网络上进行交易所需的长度。建议您创建一个新的ArConnect钱包,并将您的资产转移到新钱包中。",
"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"
@@ -791,6 +799,10 @@
"message": "生成钱包中...",
"description": "Generating wallet in progress text"
},
+ "longer_than_usual": {
+ "message": "请稍等,这比平常需要更长的时间...",
+ "description": "Longer than usual text"
+ },
"keyfile": {
"message": "密钥文件",
"description": "Keyfile text"
diff --git a/src/components/dashboard/subsettings/AddWallet.tsx b/src/components/dashboard/subsettings/AddWallet.tsx
index d48e8292..a1767f30 100644
--- a/src/components/dashboard/subsettings/AddWallet.tsx
+++ b/src/components/dashboard/subsettings/AddWallet.tsx
@@ -31,6 +31,9 @@ export default function AddWallet() {
// wallet size error modal
const walletModal = useModal();
+ // wallet generation taking longer
+ const [showLongWaitMessage, setShowLongWaitMessage] = useState(false);
+
// toasts
const { setToast } = useToasts();
@@ -112,6 +115,7 @@ export default function AddWallet() {
const finishUp = () => {
// reset before unload
window.onbeforeunload = null;
+ setShowLongWaitMessage(false);
setLoading(false);
};
@@ -131,17 +135,26 @@ export default function AddWallet() {
}
try {
+ const startTime = Date.now();
// load jwk from seedphrase input state
- const jwk =
+ let jwk =
typeof providedWallet === "string"
? await jwkFromMnemonic(providedWallet)
: providedWallet;
- const { actualLength, expectedLength } = await getWalletKeyLength(jwk);
+ let { actualLength, expectedLength } = await getWalletKeyLength(jwk);
if (expectedLength !== actualLength) {
- walletModal.setOpen(true);
- finishUp();
- return;
+ if (typeof providedWallet !== "string") {
+ walletModal.setOpen(true);
+ finishUp();
+ return;
+ } else {
+ while (expectedLength !== actualLength) {
+ setShowLongWaitMessage(Date.now() - startTime > 30000);
+ jwk = await jwkFromMnemonic(providedWallet);
+ ({ actualLength, expectedLength } = await getWalletKeyLength(jwk));
+ }
+ }
}
await addWallet(jwk, passwordInput.state);
@@ -187,15 +200,25 @@ export default function AddWallet() {
async function generateWallet() {
setGenerating(true);
+ const startTime = Date.now();
+
// generate a seedphrase
const seedphrase = await bip39.generateMnemonic();
setGeneratedWallet({ seedphrase });
// generate from seedphrase
- const jwk = await jwkFromMnemonic(seedphrase);
+ let jwk = await jwkFromMnemonic(seedphrase);
+
+ let { actualLength, expectedLength } = await getWalletKeyLength(jwk);
+ while (expectedLength !== actualLength) {
+ setShowLongWaitMessage(Date.now() - startTime > 30000);
+ jwk = await jwkFromMnemonic(seedphrase);
+ ({ actualLength, expectedLength } = await getWalletKeyLength(jwk));
+ }
setGeneratedWallet((val) => ({ ...val, jwk }));
+ setShowLongWaitMessage(false);
setGenerating(false);
return { jwk, seedphrase };
@@ -337,6 +360,11 @@ export default function AddWallet() {
{browser.i18n.getMessage("generate_wallet")}
+ {(generating || loading) && showLongWaitMessage && (
+
+ {browser.i18n.getMessage("longer_than_usual")}
+
+ )}
diff --git a/src/routes/popup/passwordPopup.tsx b/src/routes/popup/passwordPopup.tsx
index e9648c10..0b0f0d76 100644
--- a/src/routes/popup/passwordPopup.tsx
+++ b/src/routes/popup/passwordPopup.tsx
@@ -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,
diff --git a/src/routes/welcome/generate/backup.tsx b/src/routes/welcome/generate/backup.tsx
index 846ea723..38976d24 100644
--- a/src/routes/welcome/generate/backup.tsx
+++ b/src/routes/welcome/generate/backup.tsx
@@ -1,6 +1,6 @@
import { ButtonV2, Spacer, Text } 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";
@@ -20,7 +20,10 @@ export default function Backup() {
const [shown, setShown] = useState(false);
// wallet context
- const generatedWallet = useContext(WalletContext);
+ const { wallet: generatedWallet } = useContext(WalletContext);
+
+ // ref to track the latest generated wallet
+ const walletRef = useRef(generatedWallet);
// route
const [, params] = useRoute<{ setup: string; page: string }>("/:setup/:page");
@@ -36,6 +39,10 @@ export default function Backup() {
setTimeout(() => setCopyDisplay(true), 1050);
}
+ useEffect(() => {
+ walletRef.current = generatedWallet;
+ }, [generatedWallet]);
+
// Segment
useEffect(() => {
trackPage(PageType.ONBOARD_BACKUP);
diff --git a/src/routes/welcome/generate/confirm.tsx b/src/routes/welcome/generate/confirm.tsx
index 96a4d46a..6e243010 100644
--- a/src/routes/welcome/generate/confirm.tsx
+++ b/src/routes/welcome/generate/confirm.tsx
@@ -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();
diff --git a/src/routes/welcome/generate/done.tsx b/src/routes/welcome/generate/done.tsx
index c9bebde0..89f2a93e 100644
--- a/src/routes/welcome/generate/done.tsx
+++ b/src/routes/welcome/generate/done.tsx
@@ -5,7 +5,7 @@ import { formatAddress } from "~utils/format";
import Paragraph from "~components/Paragraph";
import browser from "webextension-polyfill";
import { addWallet } from "~wallets";
-import { useContext, useEffect } from "react";
+import { useContext, useEffect, useRef, useState } from "react";
import {
EventType,
PageType,
@@ -22,7 +22,14 @@ import { addExpiration } from "~wallets/auth";
export default function Done() {
// wallet context
- const wallet = useContext(WalletContext);
+ const { wallet } = useContext(WalletContext);
+ const walletRef = useRef(wallet);
+
+ // loading
+ const [loading, setLoading] = useState(false);
+
+ // wallet generation taking longer
+ const [showLongWaitMessage, setShowLongWaitMessage] = useState(false);
const [, setLocation] = useLocation();
@@ -36,13 +43,32 @@ export default function Done() {
// add generated wallet
async function done() {
+ if (loading) return;
+
+ const startTime = Date.now();
+
+ setLoading(true);
// add wallet
let nickname: string;
- if (!wallet.address || !wallet.jwk) return;
+ if (!walletRef.current.address || !walletRef.current.jwk) {
+ await new Promise((resolve) => {
+ const checkState = setInterval(() => {
+ if (walletRef.current.jwk) {
+ clearInterval(checkState);
+ resolve(null);
+ }
+ if (!showLongWaitMessage) {
+ setShowLongWaitMessage(Date.now() - startTime > 10000);
+ }
+ }, 1000);
+ });
+ }
try {
- const ansProfile = (await getAnsProfile(wallet.address)) as AnsUser;
+ const ansProfile = (await getAnsProfile(
+ walletRef.current.address
+ )) as AnsUser;
if (ansProfile) {
nickname = ansProfile.currentLabel;
@@ -51,7 +77,9 @@ export default function Done() {
// add the wallet
await addWallet(
- nickname ? { nickname, wallet: wallet.jwk } : wallet.jwk,
+ nickname
+ ? { nickname, wallet: walletRef.current.jwk }
+ : walletRef.current.jwk,
password
);
@@ -68,6 +96,12 @@ export default function Done() {
// redirect to getting started pages
setLocation("/getting-started/1");
+
+ setShowLongWaitMessage(false);
+ setLoading(false);
+
+ // reset before unload
+ window.onbeforeunload = null;
}
useEffect(() => {
@@ -90,6 +124,10 @@ export default function Done() {
getLocation();
}, []);
+ useEffect(() => {
+ walletRef.current = wallet;
+ }, [wallet]);
+
// Segment
useEffect(() => {
trackPage(PageType.ONBOARD_COMPLETE);
@@ -113,9 +151,14 @@ export default function Done() {
{browser.i18n.getMessage("analytics_title")}
-
+
{browser.i18n.getMessage("done")}
+ {loading && showLongWaitMessage && (
+
+ {browser.i18n.getMessage("longer_than_usual")}
+
+ )}
>
);
}
diff --git a/src/routes/welcome/gettingStarted.tsx b/src/routes/welcome/gettingStarted.tsx
index cd74a154..a79d7a20 100644
--- a/src/routes/welcome/gettingStarted.tsx
+++ b/src/routes/welcome/gettingStarted.tsx
@@ -38,6 +38,8 @@ export default function GettingStarted({ page }) {
if (pageNum < 5) {
setLocation(`/getting-started/${pageNum}`);
} else {
+ // reset before unload
+ window.onbeforeunload = null;
window.top.close();
}
};
diff --git a/src/routes/welcome/load/done.tsx b/src/routes/welcome/load/done.tsx
index 329c7d86..fdbc4536 100644
--- a/src/routes/welcome/load/done.tsx
+++ b/src/routes/welcome/load/done.tsx
@@ -25,6 +25,9 @@ export default function Done() {
await setAnalytics(false);
}
+ // reset before unload
+ window.onbeforeunload = null;
+
// redirect to getting started pages
setLocation("/getting-started/1");
}
diff --git a/src/routes/welcome/load/password.tsx b/src/routes/welcome/load/password.tsx
index e961db78..16e6b9bb 100644
--- a/src/routes/welcome/load/password.tsx
+++ b/src/routes/welcome/load/password.tsx
@@ -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
diff --git a/src/routes/welcome/load/wallets.tsx b/src/routes/welcome/load/wallets.tsx
index 25e37d62..2b579101 100644
--- a/src/routes/welcome/load/wallets.tsx
+++ b/src/routes/welcome/load/wallets.tsx
@@ -34,6 +34,9 @@ export default function Wallets() {
// password context
const { password } = useContext(PasswordContext);
+ // wallet generation taking longer
+ const [showLongWaitMessage, setShowLongWaitMessage] = useState(false);
+
// migration available
const [oldState] = useStorage({
key: OLD_STORAGE_NAME,
@@ -110,6 +113,7 @@ export default function Wallets() {
const finishUp = () => {
// reset before unload
window.onbeforeunload = null;
+ setShowLongWaitMessage(false);
setLoading(false);
};
@@ -135,16 +139,28 @@ export default function Wallets() {
if (loadedWallet) {
// load jwk from seedphrase input state
- const jwk =
+ const startTime = Date.now();
+
+ let jwk =
typeof loadedWallet === "string"
? await jwkFromMnemonic(loadedWallet)
: loadedWallet;
- const { expectedLength, actualLength } = await getWalletKeyLength(jwk);
+ let { actualLength, expectedLength } = await getWalletKeyLength(jwk);
if (expectedLength !== actualLength) {
- walletModal.setOpen(true);
- finishUp();
- return;
+ if (typeof loadedWallet !== "string") {
+ walletModal.setOpen(true);
+ finishUp();
+ return;
+ } else {
+ while (expectedLength !== actualLength) {
+ setShowLongWaitMessage(Date.now() - startTime > 30000);
+ jwk = await jwkFromMnemonic(loadedWallet);
+ ({ actualLength, expectedLength } = await getWalletKeyLength(
+ jwk
+ ));
+ }
+ }
}
// add wallet
@@ -214,6 +230,11 @@ export default function Wallets() {
{browser.i18n.getMessage("next")}
+ {loading && showLongWaitMessage && (
+
+ {browser.i18n.getMessage("longer_than_usual")}
+
+ )}
(
- {}
- );
+ const [generatedWallet, setGeneratedWallet] = useState({});
const navigate = () => {
setLocation(`/${params.setup}/${page - 1}`);
};
- useEffect(() => {
- (async () => {
- // only generate wallet if the
- // setup mode is wallet generation
- if (!isGenerateWallet || generatedWallet.address) return;
+ async function generateWallet() {
+ // only generate wallet if the
+ // setup mode is wallet generation
+ if (!isGenerateWallet || generatedWallet.address) return;
- // prevent user from closing the window
- // while ArConnect is generating a wallet
- window.onbeforeunload = () =>
- browser.i18n.getMessage("close_tab_generate_wallet_message");
+ // prevent user from closing the window
+ // while ArConnect is generating a wallet
+ window.onbeforeunload = () =>
+ browser.i18n.getMessage("close_tab_generate_wallet_message");
- try {
- const arweave = new Arweave(defaultGateway);
+ try {
+ const arweave = new Arweave(defaultGateway);
- // generate seed
- const seed = await bip39.generateMnemonic();
+ // generate seed
+ const seed = await bip39.generateMnemonic();
- setGeneratedWallet({ mnemonic: seed });
+ setGeneratedWallet({ mnemonic: seed });
- // generate wallet from seedphrase
- const generatedKeyfile = await jwkFromMnemonic(seed);
+ // generate wallet from seedphrase
+ let generatedKeyfile = await jwkFromMnemonic(seed);
- setGeneratedWallet((val) => ({ ...val, jwk: generatedKeyfile }));
+ let { actualLength, expectedLength } = await getWalletKeyLength(
+ generatedKeyfile
+ );
+ while (expectedLength !== actualLength) {
+ generatedKeyfile = await jwkFromMnemonic(seed);
+ ({ actualLength, expectedLength } = await getWalletKeyLength(
+ generatedKeyfile
+ ));
+ }
- // get address
- const address = await arweave.wallets.jwkToAddress(generatedKeyfile);
+ setGeneratedWallet((val) => ({ ...val, jwk: generatedKeyfile }));
- setGeneratedWallet((val) => ({ ...val, address }));
- } catch (e) {
- console.log("Error generating wallet", e);
- setToast({
- type: "error",
- content: browser.i18n.getMessage("error_generating_wallet"),
- duration: 2300
- });
- }
+ // get address
+ const address = await arweave.wallets.jwkToAddress(generatedKeyfile);
+
+ setGeneratedWallet((val) => ({ ...val, address }));
+
+ return generatedWallet;
+ } catch (e) {
+ console.log("Error generating wallet", e);
+ setToast({
+ type: "error",
+ content: browser.i18n.getMessage("error_generating_wallet"),
+ duration: 2300
+ });
+ }
- // reset before unload
- window.onbeforeunload = null;
- })();
+ return {};
+ }
+
+ useEffect(() => {
+ generateWallet();
}, [isGenerateWallet]);
// animate content sice
@@ -189,7 +201,9 @@ export default function Setup({ setupMode, page }: Props) {
-
+
@@ -290,9 +304,17 @@ export const PasswordContext = createContext({
password: ""
});
-export const WalletContext = createContext({});
+export const WalletContext = createContext({
+ wallet: {},
+ generateWallet: (retry?: boolean) => Promise.resolve({})
+});
interface WalletContextValue {
+ wallet: GeneratedWallet;
+ generateWallet: (retry?: boolean) => Promise;
+}
+
+interface GeneratedWallet {
address?: string;
mnemonic?: string;
jwk?: JWKInterface;