Skip to content

Commit

Permalink
feat: Enable import of zero balance account w/ link (testnet)
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick1904 committed May 6, 2022
1 parent b8c6394 commit cfe7f83
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { KeyPair } from 'near-api-js';
import { parseSeedPhrase } from 'near-seed-phrase';
import React from 'react';
import { useDispatch } from 'react-redux';

import {
redirectTo,
refreshAccount
} from '../../redux/actions/account';
import { showCustomAlert, clearGlobalAlert } from '../../redux/actions/status';
import { getImplicitAccountIdFromSeedPhrase, getKeyPairFromSeedPhrase } from '../../utils/parseSeedPhrase';
import { wallet } from '../../utils/wallet';
import CouldNotFindAccountModal from './CouldNotFindAccountModal';

export default ({
isOpen,
onClose,
seedPhrase
}) => {
const dispatch = useDispatch();
return (
<CouldNotFindAccountModal
isOpen={isOpen}
onClose={onClose}
onClickImport={async () => {
const recoveryKeyPair = getKeyPairFromSeedPhrase(seedPhrase);
const implicitAccountId = getImplicitAccountIdFromSeedPhrase(seedPhrase);
try {
await wallet.importZeroBalanceAccount(implicitAccountId, recoveryKeyPair);
dispatch(refreshAccount());
dispatch(redirectTo('/'));
dispatch(clearGlobalAlert());
} catch (e) {
dispatch(showCustomAlert({
success: false,
messageCodeHeader: 'error',
messageCode: 'walletErrorCodes.recoverAccountSeedPhrase.errorNotAbleToImportAccount',
errorMessage: e.message
}));
}
}}
/>
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { getRouter } from 'connected-react-router';
import { KeyPair } from 'near-api-js';
import { parseSeedPhrase } from 'near-seed-phrase';
import { parse as parseQuery, stringify } from 'query-string';
import React, { Component } from 'react';
import { Translate } from 'react-localize-redux';
Expand All @@ -17,14 +15,13 @@ import {
refreshAccount,
clearAccountState
} from '../../redux/actions/account';
import { clearLocalAlert, showCustomAlert, clearGlobalAlert } from '../../redux/actions/status';
import { clearLocalAlert, showCustomAlert } from '../../redux/actions/status';
import { selectAccountSlice } from '../../redux/slices/account';
import { selectActionsPending, selectStatusLocalAlert, selectStatusMainLoader } from '../../redux/slices/status';
import isValidSeedPhrase from '../../utils/isValidSeedPhrase';
import parseFundingOptions from '../../utils/parseFundingOptions';
import { wallet } from '../../utils/wallet';
import Container from '../common/styled/Container.css';
import CouldNotFindAccountModal from './CouldNotFindAccountModal';
import CouldNotFindAccountModalWrapper from './CouldNotFindAccountModalWrapper';
import RecoverAccountSeedPhraseForm from './RecoverAccountSeedPhraseForm';

const StyledContainer = styled(Container)`
Expand Down Expand Up @@ -157,27 +154,10 @@ class RecoverAccountSeedPhrase extends Component {
/>
</form>
{showCouldNotFindAccountModal && (
<CouldNotFindAccountModal
onClickImport={async () => {
const { secretKey } = parseSeedPhrase(seedPhrase);
const recoveryKeyPair = KeyPair.fromString(secretKey);
const implicitAccountId = Buffer.from(recoveryKeyPair.publicKey.data).toString('hex');
try {
await wallet.importZeroBalanceAccount(implicitAccountId, recoveryKeyPair);
this.props.refreshAccount();
this.props.redirectTo('/');
this.props.clearGlobalAlert();
} catch (e) {
this.props.showCustomAlert({
success: false,
messageCodeHeader: 'error',
messageCode: 'walletErrorCodes.recoverAccountSeedPhrase.errorNotAbleToImportAccount',
errorMessage: e.message
});
}
}}
<CouldNotFindAccountModalWrapper
onClose={() => this.setState({ showCouldNotFindAccountModal: false })}
isOpen={showCouldNotFindAccountModal}
seedPhrase={seedPhrase}
/>
)}
</StyledContainer>
Expand All @@ -192,8 +172,7 @@ const mapDispatchToProps = {
refreshAccount,
clearLocalAlert,
clearAccountState,
showCustomAlert,
clearGlobalAlert
showCustomAlert
};

const mapStateToProps = (state, { match }) => ({
Expand Down
89 changes: 55 additions & 34 deletions packages/frontend/src/routes/ImportAccountWithLinkWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useParams } from 'react-router-dom';

import { IMPORT_ZERO_BALANCE_ACCOUNT } from '../../../../features';
import CouldNotFindAccountModalWrapper from '../components/accounts/CouldNotFindAccountModalWrapper';
import ImportAccountWithLink from '../components/accounts/import/ImportAccountWithLink';
import { Mixpanel } from '../mixpanel/index';
import {
Expand All @@ -15,18 +17,28 @@ import { showCustomAlert } from '../redux/actions/status';
import { selectAccountId } from '../redux/slices/account';
import { selectAvailableAccounts } from '../redux/slices/availableAccounts';
import { getAccountIdsBySeedPhrase } from '../utils/helper-api';
import { getImplicitAccountIdFromSeedPhrase } from '../utils/parseSeedPhrase';

export function ImportAccountWithLinkWrapper() {
const dispatch = useDispatch();
const { seedPhrase } = useParams();
const { seedPhrase, accountId } = useParams();
const activeAccountId = useSelector(selectAccountId);
const availableAccounts = useSelector(selectAvailableAccounts);
const [accountIdsBySeedPhrase, setAccountIdsBySeedPhrase] = useState([]);
const [importingAccount, setImportingAccount] = useState(null);
const [showCouldNotFindAccountModal, setShowCouldNotFindAccountModal] = useState(false);

useEffect(() => {
const handleGetAccountsBySeedPhrase = async () => {
const accountIdsBySeedPhrase = await getAccountIdsBySeedPhrase(seedPhrase);

if (IMPORT_ZERO_BALANCE_ACCOUNT) {
const implicitAccountId = getImplicitAccountIdFromSeedPhrase(seedPhrase);
if (accountIdsBySeedPhrase.length === 0 && accountId === implicitAccountId) {
setShowCouldNotFindAccountModal(true);
}
}

setAccountIdsBySeedPhrase(accountIdsBySeedPhrase);
};
handleGetAccountsBySeedPhrase();
Expand All @@ -38,40 +50,49 @@ export function ImportAccountWithLinkWrapper() {
}));

return (
<ImportAccountWithLink
accountsBySeedPhrase={accountsBySeedPhrase}
importingAccount={importingAccount}
onClickAccount={async ({ accountId, action }) => {
if (action === 'import') {
await Mixpanel.withTracking('IE Recover with link',
async () => {
const shouldCreateFullAccessKey = false;
setImportingAccount(accountId);
await dispatch(recoverAccountSeedPhrase(seedPhrase, accountId, shouldCreateFullAccessKey));
dispatch(refreshAccount());
dispatch(redirectTo('/'));
dispatch(clearAccountState());
},
(e) => {
dispatch(showCustomAlert({
success: false,
messageCodeHeader: 'error',
messageCode: 'walletErrorCodes.recoverAccountLink.error',
errorMessage: e.message
}));
throw e;
},
() => {
setImportingAccount(false);
<>
<ImportAccountWithLink
accountsBySeedPhrase={accountsBySeedPhrase}
importingAccount={importingAccount}
onClickAccount={async ({ accountId, action }) => {
if (action === 'import') {
await Mixpanel.withTracking('IE Recover with link',
async () => {
const shouldCreateFullAccessKey = false;
setImportingAccount(accountId);
await dispatch(recoverAccountSeedPhrase(seedPhrase, accountId, shouldCreateFullAccessKey));
dispatch(refreshAccount());
dispatch(redirectTo('/'));
dispatch(clearAccountState());
},
(e) => {
dispatch(showCustomAlert({
success: false,
messageCodeHeader: 'error',
messageCode: 'walletErrorCodes.recoverAccountLink.error',
errorMessage: e.message
}));
throw e;
},
() => {
setImportingAccount(false);
}
);
} else if (action === 'select') {
if (accountId !== activeAccountId) {
await dispatch(switchAccount({ accountId }));
}
);
} else if (action === 'select') {
if (accountId !== activeAccountId) {
await dispatch(switchAccount({ accountId }));
dispatch(redirectTo('/'));
}
dispatch(redirectTo('/'));
}
}}
/>
}}
/>
{showCouldNotFindAccountModal && (
<CouldNotFindAccountModalWrapper
onClose={() => setShowCouldNotFindAccountModal(false)}
isOpen={showCouldNotFindAccountModal}
seedPhrase={seedPhrase}
/>
)}
</>
);
};
14 changes: 14 additions & 0 deletions packages/frontend/src/utils/parseSeedPhrase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { KeyPair } from 'near-api-js';
import { parseSeedPhrase } from 'near-seed-phrase';

export function getImplicitAccountIdFromSeedPhrase(seedPhrase) {
const { secretKey } = parseSeedPhrase(seedPhrase);
const recoveryKeyPair = KeyPair.fromString(secretKey);
return Buffer.from(recoveryKeyPair.publicKey.data).toString('hex');
};

export function getKeyPairFromSeedPhrase(seedPhrase) {
const { secretKey } = parseSeedPhrase(seedPhrase);
return KeyPair.fromString(secretKey);
};

0 comments on commit cfe7f83

Please sign in to comment.