Skip to content

Commit

Permalink
wallet-ext: backup mnemonic view ui update & use bg service for mnemonic
Browse files Browse the repository at this point in the history
  • Loading branch information
pchrysochoidis committed Oct 11, 2022
1 parent fe97029 commit bf5134d
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 108 deletions.
19 changes: 19 additions & 0 deletions apps/wallet/src/background/Keyring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,25 @@ class Keyring {
id
)
);
} else if (
isKeyringPayload<'getMnemonic'>(payload, 'getMnemonic')
) {
if (this.#locked) {
throw new Error('Keyring is locked. Unlock it first.');
}
if (!this.#mnemonic) {
throw new Error('Error mnemonic is empty');
}
uiConnection.send(
createMessage<KeyringPayload<'getMnemonic'>>(
{
type: 'keyring',
method: 'getMnemonic',
return: this.#mnemonic,
},
id
)
);
}
} catch (e) {
uiConnection.send(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ type MethodToPayloads = {
args: string;
return: string;
};
getMnemonic: {
args: string | undefined;
return: string;
};
};

export interface KeyringPayload<Method extends keyof MethodToPayloads>
Expand Down
30 changes: 29 additions & 1 deletion apps/wallet/src/ui/app/background-client/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { lastValueFrom, take } from 'rxjs';
import { lastValueFrom, map, take } from 'rxjs';

import { createMessage } from '_messages';
import { PortStream } from '_messaging/PortStream';
import { isKeyringPayload } from '_payloads/keyring';
import { isPermissionRequests } from '_payloads/permissions';
import { isUpdateActiveOrigin } from '_payloads/tabs/updateActiveOrigin';
import { isGetTransactionRequestsResponse } from '_payloads/transactions/ui/GetTransactionRequestsResponse';
Expand Down Expand Up @@ -117,6 +118,33 @@ export class BackgroundClient {
);
}

public async getMnemonic(password?: string) {
return await lastValueFrom(
this.sendMessage(
createMessage<KeyringPayload<'getMnemonic'>>({
type: 'keyring',
method: 'getMnemonic',
args: password,
return: undefined,
})
).pipe(
take(1),
map(({ payload }) => {
if (
isKeyringPayload<'getMnemonic'>(
payload,
'getMnemonic'
) &&
payload.return
) {
return payload.return;
}
throw new Error('Mnemonic not found');
})
)
);
}

private handleIncomingMessage(msg: Message) {
if (!this._initialized || !this._dispatch) {
throw new Error(
Expand Down
189 changes: 117 additions & 72 deletions apps/wallet/src/ui/app/pages/initialize/backup/Backup.module.scss
Original file line number Diff line number Diff line change
@@ -1,77 +1,122 @@
@use '_values/colors';
@use '_values/sizing';
@use '_utils';
@use 'sass:color';

.wallet-created {
.mnemonic {
padding: 14px;
border-radius: 15px;
margin: auto;
margin-bottom: 16px;
background: colors.$white;
border: 1px solid #e9eaeb;
font-family: Inter, sans-serif;
width: 320px;
height: 90px;

@include utils.typography('header/search-text');

line-height: 130%;
color: colors.$gray-85;
}

.header-title {
text-align: left;
margin-bottom: 20px;
color: colors.$gray-100;
font-size: 30px;
font-weight: 700;
line-height: 36px;
}

.sub-title {
text-align: center;
color: colors.$gray-90;
font-weight: 600;
font-size: 18px;
line-height: 100%;
}

.success-icon {
border-radius: 50%;
width: 46px;
height: 46px;
margin: auto;
border: 3px dotted colors.$success;
display: flex;
align-items: center;
justify-content: center;

.success-bg {
background-color: colors.$success;
border-radius: 50%;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
}

i {
color: colors.$white;
font-size: 25px;
}
}

.btn {
width: 100%;
margin: auto;
max-width: 320px;
margin-top: 20px;

i {
margin-right: 10px;
font-weight: 500;
font-size: 12px;
}
}
$color: color.change(colors.$sui-blue, $alpha: 0.1);

display: flex;
flex-flow: column nowrap;
align-items: center;
justify-content: center;
padding: 40px 30px;
background: $color;
border: 1px solid $color;
border-radius: 20px;
max-width: sizing.$popup-width;
max-height: sizing.$popup-height;
flex: 1;
}

.success-icon {
border-radius: 50%;
width: 48px;
height: 48px;
min-height: 48px;
border: 3px dotted colors.$success;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 10px;
}

.success-bg {
background-color: colors.$success;
border-radius: 50%;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
}

.thumbs-up {
color: colors.$white;
font-size: 25px;
}

.header-title {
text-align: center;
margin: 0;
margin-bottom: 30px;
color: colors.$gray-90;
text-transform: capitalize;

@include utils.typography('Primary/Heading1-B');
}

.sub-title {
margin: 0;
margin-bottom: 15px;
color: colors.$gray-75;
text-transform: uppercase;

@include utils.typography('Primary/CAPTION-B');
}

.mnemonic {
display: flex;
flex-flow: column nowrap;
gap: 8px;
align-self: stretch;
font-weight: 600;
font-size: 17px;
line-height: 140%;
padding: 14px;
border-radius: 15px;
background: colors.$white;
border: 1px solid #e9eaeb;
box-shadow: 0 1px 2px rgba(16 24 40 / 5%);
color: colors.$gray-85;
}

.copy {
margin-top: 10px;
color: colors.$sui-dark-blue;
align-self: flex-end;
cursor: pointer;

@include utils.typography('Primary/CAPTION-SB');
}

.info {
text-align: center;
color: colors.$gray-75;
margin-top: 15px;

@include utils.typography('ParagraphPrimary/P2-R');
}

.info-caption {
text-align: center;
color: colors.$gray-75;
margin-bottom: 5px;

@include utils.typography('Primary/CAPTION-M');
}

.btn {
display: flex;
flex-flow: row nowrap;
gap: 8px;
margin-top: 45px;
align-self: stretch;
padding: 14px 20px;
}

.arrow-up {
font-size: 12px;
font-weight: 300;
transform: rotate(135deg);
}
76 changes: 55 additions & 21 deletions apps/wallet/src/ui/app/pages/initialize/backup/index.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,83 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { useCallback } from 'react';
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';

import Button from '_app/shared/button';
import Alert from '_components/alert';
import CopyToClipboard from '_components/copy-to-clipboard';
import Icon, { SuiIcons } from '_components/icon';
import { useAppDispatch, useAppSelector } from '_src/ui/app/hooks';
import { setMnemonic } from '_src/ui/app/redux/slices/account';
import Loading from '_components/loading';
import { useAppDispatch } from '_hooks';
import { loadMnemonicFromKeyring } from '_redux/slices/account';

import st from './Backup.module.scss';

const BackupPage = () => {
const mnemonic = useAppSelector(
({ account }) => account.createdMnemonic || account.mnemonic
);
const [loading, setLoading] = useState(true);
const [mnemonic, setLocalMnemonic] = useState<string | null>(null);
const navigate = useNavigate();
const dispatch = useAppDispatch();
const handleOnClick = useCallback(() => {
if (mnemonic) {
navigate('/');
dispatch(setMnemonic(mnemonic));
}
}, [navigate, dispatch, mnemonic]);
useEffect(() => {
// TODO: this assumes that the Keyring in bg service is unlocked. It should be fix
// when we add a locked status guard. (#encrypt-wallet)
(async () => {
setLoading(true);
try {
setLocalMnemonic(
await dispatch(loadMnemonicFromKeyring({})).unwrap()
);
} catch (e) {
// Do nothing
} finally {
setLoading(false);
}
})();
}, [dispatch]);
return (
<div className={st.walletCreated}>
<div className={st.successIcon}>
<div className={st.successBg}>
<Icon icon={SuiIcons.ThumbsUp} />
<Icon icon={SuiIcons.ThumbsUp} className={st.thumbsUp} />
</div>
</div>

<h1 className={st.headerTitle}>Wallet Successfully Created!</h1>
<h2 className={st.subTitle}>Backup Recovery Passphrase</h2>
<div className={st.mnemonic}>{mnemonic}</div>

<h1 className={st.headerTitle}>Wallet Created Successfully!</h1>
<h2 className={st.subTitle}>Recovery Phrase</h2>
<Loading loading={loading}>
{mnemonic ? (
<div className={st.mnemonic}>
{mnemonic}
<CopyToClipboard
txt={mnemonic}
className={st.copy}
mode="plain"
>
COPY
</CopyToClipboard>
</div>
) : (
<Alert>Something is wrong, Recovery Phrase is empty.</Alert>
)}
</Loading>
<div className={st.info}>
Your recovery phrase makes it easy to back up and restore your
account.
</div>
<div className={st.info}>
<div className={st.infoCaption}>WARNING</div>
Never disclose your secret recovery phrase. Anyone with the
passphrase can take over your account forever.
</div>
<Button
type="button"
className={st.btn}
size="large"
mode="primary"
onClick={handleOnClick}
onClick={() => navigate('/')}
>
<Icon icon={SuiIcons.Checkmark} className={st.success} />
Done
Open Sui Wallet
<Icon icon={SuiIcons.ArrowLeft} className={st.arrowUp} />
</Button>
</div>
);
Expand Down
Loading

0 comments on commit bf5134d

Please sign in to comment.