diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5c2f4ee6ae..7a7b9e347b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -181,9 +181,9 @@ jobs: working-directory: ../trezor-user-env run: cp -rf src/binaries/firmware/bin/trezor-emu-core-v2-master ./ - - name: Copy the trezord-go-v2.0.31 to the root of the project + - name: Copy the trezord-go-v2.0.32 to the root of the project working-directory: ../trezor-user-env - run: cp -rf src/binaries/trezord-go/bin/trezord-go-v2.0.31 ./ + run: cp -rf src/binaries/trezord-go/bin/trezord-go-v2.0.32 ./ - name: Create the logs folder in the root of the trezor-user-env working-directory: ../trezor-user-env @@ -191,7 +191,7 @@ jobs: - name: Run the trezor user environment working-directory: ../trezor-user-env - run: sudo docker run -p 9001:9001 -p 9002:9002 -p 21326:21326 -p 127.0.0.1:21325:21326 -p 21324:21324 -v logs:/trezor-user-env/logs/screens -v trezor-emu-core-v2-master:/trezor-user-env/src/binaries/firmware/bin/user_downloaded -v trezord-go-v2.0.31:/trezor-user-env/src/binaries/trezord-go/bin -d emurgornd/trezor-user-env:latest + run: sudo docker run -p 9001:9001 -p 9002:9002 -p 21326:21326 -p 127.0.0.1:21325:21326 -p 21324:21324 -v logs:/trezor-user-env/logs/screens -v trezor-emu-core-v2-master:/trezor-user-env/src/binaries/firmware/bin/user_downloaded -v trezord-go-v2.0.32:/trezor-user-env/src/binaries/trezord-go/bin -d emurgornd/trezor-user-env:latest - uses: actions/checkout@v3 diff --git a/crowdin.yml b/crowdin.yml index 99323cd8bc..ebaf0309bc 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -17,6 +17,7 @@ files: it: it-IT sk: sk-SK cs: cs-CZ + vi: vi-VN - source: /packages/yoroi-extension/app/i18n/locales/**/en-US.md translation: /packages/yoroi-extension/app/i18n/locales/**/%locale%.md languages_mapping: @@ -34,4 +35,5 @@ files: it: it-IT sk: sk-SK cs: cs-CZ + vi: vi-VN content_segmentation: 0 diff --git a/install-all.sh b/install-all.sh index 2efa699cb1..8143b1250c 100644 --- a/install-all.sh +++ b/install-all.sh @@ -1,5 +1,4 @@ npm i \ && npm i --prefix packages/yoroi-extension \ && npm i --prefix packages/yoroi-connector \ -&& npm i --prefix packages/yoroi-connector/example-ergo \ && npm i --prefix packages/yoroi-connector/example-cardano \ No newline at end of file diff --git a/packages/yoroi-extension/app/App.js b/packages/yoroi-extension/app/App.js index 1708953bc2..19b9294b34 100644 --- a/packages/yoroi-extension/app/App.js +++ b/packages/yoroi-extension/app/App.js @@ -5,24 +5,9 @@ import { observer } from 'mobx-react'; import { Router } from 'react-router-dom'; import type { RouterHistory } from 'react-router-dom'; import { addLocaleData, IntlProvider } from 'react-intl'; -import en from 'react-intl/locale-data/en'; -import ko from 'react-intl/locale-data/ko'; -import ja from 'react-intl/locale-data/ja'; -import zh from 'react-intl/locale-data/zh'; -import ru from 'react-intl/locale-data/ru'; -import de from 'react-intl/locale-data/de'; -import fr from 'react-intl/locale-data/fr'; -import nl from 'react-intl/locale-data/nl'; -import pt from 'react-intl/locale-data/pt'; -import id from 'react-intl/locale-data/id'; -import es from 'react-intl/locale-data/es'; -import it from 'react-intl/locale-data/it'; -import tr from 'react-intl/locale-data/tr'; -import cs from 'react-intl/locale-data/cs'; -import sk from 'react-intl/locale-data/sk'; import { observable, autorun, runInAction } from 'mobx'; import { Routes } from './Routes'; -import { translations } from './i18n/translations'; +import { locales, translations } from './i18n/translations'; import type { StoresMap } from './stores'; import type { ActionsMap } from './actions'; import { changeToplevelTheme, MuiThemes } from './styles/utils'; @@ -39,23 +24,7 @@ import Support from './components/widgets/Support'; import { trackNavigation } from './api/analytics'; // https://github.com/yahoo/react-intl/wiki#loading-locale-data -addLocaleData([ - ...en, - ...ko, - ...ja, - ...zh, - ...ru, - ...de, - ...fr, - ...nl, - ...pt, - ...id, - ...es, - ...it, - ...tr, - ...cs, - ...sk, -]); +addLocaleData(locales); type Props = {| +stores: StoresMap, diff --git a/packages/yoroi-extension/app/assets/images/flags/vietnamese.inline.svg b/packages/yoroi-extension/app/assets/images/flags/vietnamese.inline.svg new file mode 100644 index 0000000000..868caa51ba --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/flags/vietnamese.inline.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/components/topbar/SidebarRevamp.js b/packages/yoroi-extension/app/components/topbar/SidebarRevamp.js index cd0ce766c9..674013d98c 100644 --- a/packages/yoroi-extension/app/components/topbar/SidebarRevamp.js +++ b/packages/yoroi-extension/app/components/topbar/SidebarRevamp.js @@ -7,7 +7,7 @@ import styles from './SidebarRevamp.scss'; import type { SidebarCategoryRevamp } from '../../stores/stateless/sidebarCategories'; import { intlShape } from 'react-intl'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; -import { ReactComponent as yoroiLogo } from '../../assets/images/sidebar/yoroi_logo.inline.svg'; +import { ReactComponent as YoroiLogo } from '../../assets/images/sidebar/yoroi_logo.inline.svg'; import globalMessages from '../../i18n/global-messages'; type Props = {| @@ -15,6 +15,7 @@ type Props = {| +categories?: Array, +isActiveCategory?: SidebarCategoryRevamp => boolean, +onCategoryClicked?: SidebarCategoryRevamp => void, + +onLogoClick?: void => void, |}; @observer @@ -28,23 +29,30 @@ export default class SidebarRevamp extends Component { children: void, isActiveCategory: void, onCategoryClicked: void, + onLogoClick: void, |} = { children: undefined, categories: undefined, isActiveCategory: undefined, onCategoryClicked: undefined, + onLogoClick: undefined, }; render(): Node { const { intl } = this.context; - const { categories, isActiveCategory, onCategoryClicked } = this.props; - const YoroiLogo = yoroiLogo; + const { categories, isActiveCategory, onCategoryClicked, onLogoClick } = this.props; return (
{this.props.children}
- + {onLogoClick ? ( + + ) : ( + + )}
{categories @@ -68,8 +76,8 @@ export default class SidebarRevamp extends Component {
{intl.formatMessage(globalMessages.sidebarFaq)} diff --git a/packages/yoroi-extension/app/components/topbar/banners/TestnetWarningBanner.js b/packages/yoroi-extension/app/components/topbar/banners/TestnetWarningBanner.js index cb735ea070..67d80efdba 100644 --- a/packages/yoroi-extension/app/components/topbar/banners/TestnetWarningBanner.js +++ b/packages/yoroi-extension/app/components/topbar/banners/TestnetWarningBanner.js @@ -63,7 +63,9 @@ export default class TestnetWarningBanner extends Component {
- NOTE: Unfortunately the Ergo network support will be dropped from Yoroi in the near future. + NOTE: Due to the planned gradual termination of the Ergo wallets support in Yoroi extension, +
+ Starting with the next version any Ergo wallets in the list will be visible, but not operational!
Please make sure to migrate your Ergo funds and wallets to another application.
diff --git a/packages/yoroi-extension/app/components/topbar/banners/TestnetWarningBanner.scss b/packages/yoroi-extension/app/components/topbar/banners/TestnetWarningBanner.scss index 8b31396cab..7bd2c43f07 100644 --- a/packages/yoroi-extension/app/components/topbar/banners/TestnetWarningBanner.scss +++ b/packages/yoroi-extension/app/components/topbar/banners/TestnetWarningBanner.scss @@ -46,7 +46,7 @@ } .ergoWarning { - height: 60px; + height: 90px; display: flex; justify-content: center; align-items: center; diff --git a/packages/yoroi-extension/app/components/transfer/SuccessPage.js b/packages/yoroi-extension/app/components/transfer/SuccessPage.js index 0ee2a8a23e..24940df95c 100644 --- a/packages/yoroi-extension/app/components/transfer/SuccessPage.js +++ b/packages/yoroi-extension/app/components/transfer/SuccessPage.js @@ -1,5 +1,5 @@ // @flow -import type { Node } from 'react'; +import type { ComponentType, Node } from 'react'; import { Component } from 'react'; import { observer } from 'mobx-react'; import { intlShape } from 'react-intl'; @@ -8,6 +8,9 @@ import Dialog from '../widgets/Dialog'; import DialogCloseButton from '../widgets/DialogCloseButton'; import LoadingSpinner from '../widgets/LoadingSpinner'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; +import { Typography } from '@mui/material'; +import { withLayout } from '../../styles/context/layout'; +import type { InjectedLayoutProps } from '../../styles/context/layout'; type Props = {| +title: string, @@ -20,8 +23,7 @@ type Props = {| |}; @observer -export default class SuccessPage extends Component { - +class SuccessPage extends Component { static contextTypes: {|intl: $npm$ReactIntl$IntlFormat|} = { intl: intlShape.isRequired }; @@ -31,7 +33,7 @@ export default class SuccessPage extends Component { }; render(): Node { - const { title, text } = this.props; + const { title, text, isRevampLayout } = this.props; const actions = this.props.closeInfo == null ? undefined @@ -48,17 +50,28 @@ export default class SuccessPage extends Component { closeOnOverlayClick={false} onClose={this.props.closeInfo ? this.props.closeInfo.onClose : undefined} className={styles.dialog} - closeButton={this.props.closeInfo ? () : undefined} + closeButton={this.props.closeInfo ? : undefined} >
-
+ {title} -
-
+ + {text} -
+ {this.props.closeInfo == null && (
@@ -70,3 +83,5 @@ export default class SuccessPage extends Component { ); } } + +export default (withLayout(SuccessPage): ComponentType); \ No newline at end of file diff --git a/packages/yoroi-extension/app/components/transfer/SuccessPage.scss b/packages/yoroi-extension/app/components/transfer/SuccessPage.scss index 0c0a365baf..116c10b84a 100644 --- a/packages/yoroi-extension/app/components/transfer/SuccessPage.scss +++ b/packages/yoroi-extension/app/components/transfer/SuccessPage.scss @@ -4,25 +4,6 @@ align-items: center; justify-content: center; - .title { - color: var(--yoroi-palette-secondary-300); - text-transform: uppercase; - height: 19px; - font-weight: 500; - font-size: 16px; - font-weight: 500; - line-height: 19px; - text-align: center; - } - - .text { - color: var(--yoroi-palette-gray-800); - font-weight: 400; - font-size: 14px; - line-height: 22px; - text-align: center; - } - .spinnerSection { margin-top: 12px; margin-bottom: 5px; @@ -37,6 +18,7 @@ width: 252px; height: 194px; margin: auto; + margin-top: 30px; } } :global(.YoroiModern):global(.YoroiShelley) .component, :global(.YoroiRevamp):global(.YoroiShelley) .component { diff --git a/packages/yoroi-extension/app/components/wallet/add-wallet-revamp/AddWalletPageHeader.js b/packages/yoroi-extension/app/components/wallet/add-wallet-revamp/AddWalletPageHeader.js index 178274e812..e67ddd0939 100644 --- a/packages/yoroi-extension/app/components/wallet/add-wallet-revamp/AddWalletPageHeader.js +++ b/packages/yoroi-extension/app/components/wallet/add-wallet-revamp/AddWalletPageHeader.js @@ -6,49 +6,72 @@ import YoroiLogo from '../../../assets/images/yoroi-logo-shape-blue.inline.svg'; import { defineMessages, intlShape } from 'react-intl'; import { observer } from 'mobx-react'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; -import { Typography, Box } from '@mui/material'; +import { Typography, Box, Button } from '@mui/material'; import globalMessages from '../../../i18n/global-messages'; +import { ReactComponent as BackIcon } from '../../../assets/images/assets-page/backarrow.inline.svg'; const messages: * = defineMessages({ subtitle: { id: 'wallet.add.page.revamp.subtitle', defaultMessage: '!!!Light wallet for Cardano assets', }, + backButtonLabel: { + id: 'wallet.add.page.revamp.backButtonLabel', + defaultMessage: '!!!Back to current wallet', + }, }); +type Props = {| + +goToCurrentWallet: void => void, + +hasAnyWallets: boolean, +|}; + @observer -export default class AddWalletPageHeader extends Component<{||}> { +export default class AddWalletPageHeader extends Component { static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; render(): Node { const { intl } = this.context; + const { goToCurrentWallet, hasAnyWallets } = this.props; return ( - + + {hasAnyWallets && ( + + )} - Yoroi + + Yoroi + + + {intl.formatMessage(globalMessages.yoroi)} + + + {intl.formatMessage(messages.subtitle)} + - - {intl.formatMessage(globalMessages.yoroi)} - - - {intl.formatMessage(messages.subtitle)} - ); } diff --git a/packages/yoroi-extension/app/components/wallet/assets/AssetsList.js b/packages/yoroi-extension/app/components/wallet/assets/AssetsList.js index 70b4f15482..7fec4aa836 100644 --- a/packages/yoroi-extension/app/components/wallet/assets/AssetsList.js +++ b/packages/yoroi-extension/app/components/wallet/assets/AssetsList.js @@ -37,6 +37,7 @@ const SORTING_COLUMNS = { name: string, id: string, amount: string, + amountForSorting?: BigNumber, |} type Props = {| +assetsList: Asset[], @@ -136,6 +137,10 @@ export default class AssetsList extends Component { this.setState({ sortingDirection: newSortDirection }) if (field === 'amount') { + const dedicatedField = 'amountForSorting'; + if (a[dedicatedField] != null && b[dedicatedField] != null) { + return compareNumbers(a[dedicatedField], b[dedicatedField], newSortDirection) + } return compareNumbers(a[field], b[field], newSortDirection) } // Other fields diff --git a/packages/yoroi-extension/app/components/wallet/assets/AssetsPage.js b/packages/yoroi-extension/app/components/wallet/assets/AssetsPage.js index 635deb33f7..4a552b1f1c 100644 --- a/packages/yoroi-extension/app/components/wallet/assets/AssetsPage.js +++ b/packages/yoroi-extension/app/components/wallet/assets/AssetsPage.js @@ -24,14 +24,14 @@ type Props = {| export default class AssetsPage extends Component { render(): Node { - const { assetDeposit, network } = this.props + const { assetDeposit, network, assetsList, getTokenInfo, shouldHideBalance } = this.props; return (
diff --git a/packages/yoroi-extension/app/components/wallet/assets/TokenList.js b/packages/yoroi-extension/app/components/wallet/assets/TokenList.js index accf777f27..61fc2b36fb 100644 --- a/packages/yoroi-extension/app/components/wallet/assets/TokenList.js +++ b/packages/yoroi-extension/app/components/wallet/assets/TokenList.js @@ -33,6 +33,7 @@ import { Link } from 'react-router-dom'; import { ROUTES } from '../../../routes-config'; import CopyToClipboardText from '../../widgets/CopyToClipboardLabel'; import { ListEmpty } from './ListEmpty'; +import BigNumber from 'bignumber.js'; const SORTING_DIRECTIONS = { UP: 'UP', @@ -48,6 +49,7 @@ export type Asset = {| name: string, id: string, amount: string, + amountForSorting?: BigNumber, |}; type Props = {| +assetsList: Asset[], @@ -90,6 +92,10 @@ function TokenList({ assetsList: list, shouldHideBalance, intl }: Props & Intl): setState({ ...state, sortingDirection: newSortDirection }); if (field === SORTING_COLUMNS.AMOUNT) { + const dedicatedField = 'amountForSorting'; + if (a[dedicatedField] != null && b[dedicatedField] != null) { + return compareNumbers(a[dedicatedField], b[dedicatedField], newSortDirection); + } return compareNumbers(a[field], b[field], newSortDirection); } // Other fields diff --git a/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js b/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js index 7276c45bd1..fc592a6347 100644 --- a/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js +++ b/packages/yoroi-extension/app/components/wallet/send/TransactionSuccessDialog.js @@ -4,33 +4,35 @@ import type { Node } from 'react'; import { Component } from 'react'; import { observer } from 'mobx-react'; import { defineMessages, intlShape } from 'react-intl'; -import SuccessPage from '../../transfer/SuccessPage'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; +import Dialog from '../../widgets/Dialog'; +import { Stack, Typography } from '@mui/material'; +import DialogCloseButton from '../../widgets/DialogCloseButton'; +import { ReactComponent as SuccessImg } from '../../../assets/images/transfer-success.inline.svg'; const messages = defineMessages({ title: { id: 'wallet.transaction.success.title', - defaultMessage: '!!!Successfully sent', + defaultMessage: '!!!Transaction submitted', }, buttonLabel: { id: 'wallet.transaction.success.button.label', - defaultMessage: '!!!Transaction page', + defaultMessage: '!!!Go To Transactions', }, explanation: { id: 'wallet.transaction.success.explanation', - defaultMessage: '!!!Track the status of the transaction from the Transactions page', - } + defaultMessage: '!!!Check this transaction in the list of wallet transactions', + }, }); type Props = {| - +onClose: void => PossiblyAsync; + +onClose: void => PossiblyAsync, +classicTheme: boolean, |}; @observer export default class TransactionSuccessDialog extends Component { - - static contextTypes: {|intl: $npm$ReactIntl$IntlFormat|} = { + static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; @@ -38,15 +40,31 @@ export default class TransactionSuccessDialog extends Component { const { intl } = this.context; return ( - + actions={[ + { + label: intl.formatMessage(messages.buttonLabel), + onClick: this.props.onClose, + primary: true, + }, + ]} + onClose={this.props.onClose} + closeButton={} + > + + + + {intl.formatMessage(messages.explanation)} + + + ); } } diff --git a/packages/yoroi-extension/app/components/wallet/staking/dashboard-revamp/RewardHistoryDialog.js b/packages/yoroi-extension/app/components/wallet/staking/dashboard-revamp/RewardHistoryDialog.js index ab3fcde47c..a232cf47d0 100644 --- a/packages/yoroi-extension/app/components/wallet/staking/dashboard-revamp/RewardHistoryDialog.js +++ b/packages/yoroi-extension/app/components/wallet/staking/dashboard-revamp/RewardHistoryDialog.js @@ -7,7 +7,7 @@ import globalMessages from '../../../../i18n/global-messages'; import DialogCloseButton from '../../../widgets/DialogCloseButton'; import { Typography } from '@mui/material'; import Dialog from '../../../widgets/Dialog'; -import { injectIntl } from 'react-intl'; +import { injectIntl, defineMessages } from 'react-intl'; import type { $npm$ReactIntl$IntlShape } from 'react-intl'; import { Box } from '@mui/system'; import { RewardHistoryItem } from './RewardHistoryTab'; @@ -19,6 +19,13 @@ import LocalizableError from '../../../../i18n/LocalizableError'; import { groupByPoolName } from '../utils'; import styles from './RewardHistoryDialog.scss'; +const messages = defineMessages({ + epoch: { + id: 'wallet.staking.rewards.rewardHistory.epochNum', + defaultMessage: '!!!Epoch {number}', + }, +}); + export type GraphRewardData = {| error: ?LocalizableError, items: Array<{| @@ -41,8 +48,7 @@ type Intl = {| function RewardHistoryDialog({ graphData, onClose, intl }: Props & Intl): Node { const rewardItems = graphData.rewardsGraphData.items; - const rewardList = rewardItems?.totalRewards.filter(p => Boolean(p.primary)) ?? []; - + const rewardList = rewardItems?.perEpochRewards.filter(p => Boolean(p.primary)) ?? []; const rewardsByPoolName = useMemo(() => groupByPoolName(rewardList), []); return ( @@ -76,13 +82,13 @@ function RewardHistoryDialog({ graphData, onClose, intl }: Props & Intl): Node { key={poolName} // $FlowFixMe[incompatible-use]: Object entries flow type poolId={data.poolId} - poolName={poolName} + poolName={poolName || '-'} // $FlowFixMe[incompatible-use]: Object entries flow type poolAvatar={data.poolAvatar} // $FlowFixMe[incompatible-use]: Object entries flow type historyList={data.map(item => ({ // TODO: Make sure it's "received" in all use cases - type: 'Received', + type: intl.formatMessage(messages.epoch, { number: item.name }), date: item.date, balance: item.primary, currency: item.currency, diff --git a/packages/yoroi-extension/app/components/wallet/staking/dashboard-revamp/RewardHistoryGraph.js b/packages/yoroi-extension/app/components/wallet/staking/dashboard-revamp/RewardHistoryGraph.js index 4766771bb5..7d41363dfc 100644 --- a/packages/yoroi-extension/app/components/wallet/staking/dashboard-revamp/RewardHistoryGraph.js +++ b/packages/yoroi-extension/app/components/wallet/staking/dashboard-revamp/RewardHistoryGraph.js @@ -1,7 +1,7 @@ // @flow import type { ComponentType, Node } from 'react'; import { Box, styled } from '@mui/system'; -import { Stack, Typography } from '@mui/material'; +import { Button, Stack, Typography } from '@mui/material'; import { defineMessages, injectIntl } from 'react-intl'; import globalMessages from '../../../../i18n/global-messages'; import type { $npm$ReactIntl$IntlShape } from 'react-intl'; @@ -188,19 +188,14 @@ function RewardHistoryGraph({ return ( - - {title} - + + + {rewardsGraphData.error && (
diff --git a/packages/yoroi-extension/app/components/wallet/transactions/TransactionRevamp.js b/packages/yoroi-extension/app/components/wallet/transactions/TransactionRevamp.js index c52fa19451..fb207d2929 100644 --- a/packages/yoroi-extension/app/components/wallet/transactions/TransactionRevamp.js +++ b/packages/yoroi-extension/app/components/wallet/transactions/TransactionRevamp.js @@ -47,7 +47,7 @@ import CopyableAddress from '../../widgets/CopyableAddress'; import { genAddressLookup } from '../../../stores/stateless/addressStores'; import { MultiToken } from '../../../api/common/lib/MultiToken'; import { hiddenAmount } from '../../../utils/strings'; -import { getTokenName, getTokenIdentifierIfExists } from '../../../stores/stateless/tokenHelpers'; +import { getTokenName, getTokenIdentifierIfExists, assetNameFromIdentifier } from '../../../stores/stateless/tokenHelpers'; import { parseMetadata, parseMetadataDetailed, @@ -198,11 +198,12 @@ export default class TransactionRevamp extends Component { return {hiddenAmount}; } const tokenInfo = this.props.getTokenInfo(request.entry); - const shiftedAmount = request.entry.amount.shiftedBy(-tokenInfo.Metadata.numberOfDecimals); + const numberOfDecimals = tokenInfo?.Metadata.numberOfDecimals ?? 0; + const shiftedAmount = request.entry.amount.shiftedBy(-numberOfDecimals); const [beforeDecimalRewards, afterDecimalRewards] = splitAmount( shiftedAmount, - tokenInfo.Metadata.numberOfDecimals + numberOfDecimals, ); // we may need to explicitly add + for positive values @@ -353,12 +354,14 @@ export default class TransactionRevamp extends Component { getTicker: TokenEntry => string = tokenEntry => { const tokenInfo = this.props.getTokenInfo(tokenEntry); - return truncateToken(getTokenName(tokenInfo)); + return tokenInfo != null + ? truncateToken(getTokenName(tokenInfo)) + : assetNameFromIdentifier(tokenEntry.identifier); }; getFingerprint: TokenEntry => string | void = tokenEntry => { const tokenInfo = this.props.getTokenInfo(tokenEntry); - if (tokenInfo.Metadata.type === 'Cardano') { + if (tokenInfo?.Metadata.type === 'Cardano') { return getTokenIdentifierIfExists(tokenInfo); } return undefined; @@ -896,29 +899,38 @@ export default class TransactionRevamp extends Component { const { intl } = this.context; if (data instanceof CardanoShelleyTransaction && data.metadata !== null) { - let jsonData = null; - - try { - jsonData = parseMetadata(data.metadata); - } catch (error) { - // try to parse schema using detailed conversion if advanced user - if (this.props.complexityLevel === ComplexityLevels.Advanced) { - try { - jsonData = parseMetadataDetailed(data.metadata); - } catch (errDetailed) { - // discard error - // can not parse metadata as json - // show the metadata hex as is + let metadata; + if (typeof data.metadata === 'string') { + let jsonData = null; + + try { + jsonData = parseMetadata(data.metadata); + } catch (error) { + // try to parse schema using detailed conversion if advanced user + if (this.props.complexityLevel === ComplexityLevels.Advanced) { + try { + jsonData = parseMetadataDetailed(data.metadata); + } catch (errDetailed) { + // discard error + // can not parse metadata as json + // show the metadata hex as is + } } + // do nothing for simple user + } + if (jsonData !== null) { + metadata = (); + } else { + metadata = (0x{data.metadata}); } - // do nothing for simple user + } else { + metadata = ({JSON.stringify(data.metadata, null, 2)} } />); } - return (

{intl.formatMessage(messages.transactionMetadata)}

- {jsonData !== null ? : 0x{data.metadata}} + {metadata}
); diff --git a/packages/yoroi-extension/app/components/widgets/CodeBlock.js b/packages/yoroi-extension/app/components/widgets/CodeBlock.js index 6f974dc3d4..1a7246f7a4 100644 --- a/packages/yoroi-extension/app/components/widgets/CodeBlock.js +++ b/packages/yoroi-extension/app/components/widgets/CodeBlock.js @@ -5,7 +5,7 @@ import { observer } from 'mobx-react'; import styles from './CodeBlock.scss'; type Props = {| - +code: string, + +code: string | Node, |}; @observer diff --git a/packages/yoroi-extension/app/components/widgets/FlagLabel.js b/packages/yoroi-extension/app/components/widgets/FlagLabel.js index dd9aa19f35..29b519ac28 100644 --- a/packages/yoroi-extension/app/components/widgets/FlagLabel.js +++ b/packages/yoroi-extension/app/components/widgets/FlagLabel.js @@ -18,7 +18,7 @@ export default class FlagLabel extends Component { return (
- + { typeof svg === 'string' ? svg : ()} {label}
); diff --git a/packages/yoroi-extension/app/connector/components/connect/ConnectPage.js b/packages/yoroi-extension/app/connector/components/connect/ConnectPage.js index bc5498b9f0..9c4dae0fd3 100644 --- a/packages/yoroi-extension/app/connector/components/connect/ConnectPage.js +++ b/packages/yoroi-extension/app/connector/components/connect/ConnectPage.js @@ -244,6 +244,7 @@ class ConnectPage extends Component { type="password" {...walletPasswordField.bind()} error={walletPasswordField.error} + id="walletPassword" /> )}
@@ -253,6 +254,7 @@ class ConnectPage extends Component { variant={isRevampLayout ? 'outlined' : 'secondary'} onClick={this.hidePasswordForm} sx={{ minWidth: 'auto' }} + id="backButton" > {intl.formatMessage(globalMessages.backButtonLabel)} @@ -263,6 +265,7 @@ class ConnectPage extends Component { fullWidth disabled={!walletPasswordField.isValid} onClick={this.submit} + id="confirmButton" > {intl.formatMessage(globalMessages.confirm)} diff --git a/packages/yoroi-extension/app/connector/components/signin/AddCollateralPage.js b/packages/yoroi-extension/app/connector/components/signin/AddCollateralPage.js index 8f6a110af7..674dfa52d5 100644 --- a/packages/yoroi-extension/app/connector/components/signin/AddCollateralPage.js +++ b/packages/yoroi-extension/app/connector/components/signin/AddCollateralPage.js @@ -263,6 +263,7 @@ class AddCollateralPage extends Component { fontWeight={500} marginBottom="8px" fontSize="20px" + id="addCollateralTitle" > {intl.formatMessage(messages.reorgTitle)} @@ -291,7 +292,7 @@ class AddCollateralPage extends Component { > {intl.formatMessage(globalMessages.amount)} - + {this.renderAmountDisplay({ entry: { identifier: txData.fee.tokenId, @@ -303,7 +304,7 @@ class AddCollateralPage extends Component { {intl.formatMessage(signTxMessages.transactionFee)} - + {this.renderAmountDisplay({ entry: { identifier: txData.fee.tokenId, @@ -321,6 +322,7 @@ class AddCollateralPage extends Component { type="password" {...walletPasswordField.bind()} error={walletPasswordField.error} + id="walletPassword" /> {submissionError === 'SEND_TX_ERROR' && ( {intl.formatMessage(messages.sendError)} @@ -355,6 +357,7 @@ class AddCollateralPage extends Component { variant="outlined" color="primary" onClick={onCancel} + id="cancelButton" > {intl.formatMessage(globalMessages.backButtonLabel)} @@ -365,6 +368,7 @@ class AddCollateralPage extends Component { disabled={walletType === 'web' && !walletPasswordField.isValid} onClick={this.submit.bind(this)} loading={isSubmitting} + id="confirmButton" > {intl.formatMessage(confirmButtonLabel)} diff --git a/packages/yoroi-extension/app/connector/components/signin/CardanoSignTxPage.js b/packages/yoroi-extension/app/connector/components/signin/CardanoSignTxPage.js index 67fa143975..242eda283a 100644 --- a/packages/yoroi-extension/app/connector/components/signin/CardanoSignTxPage.js +++ b/packages/yoroi-extension/app/connector/components/signin/CardanoSignTxPage.js @@ -392,6 +392,7 @@ class SignTxPage extends Component { type="password" {...walletPasswordField.bind()} error={walletPasswordField.error} + id="walletPassword" /> } /> @@ -422,7 +423,7 @@ class SignTxPage extends Component { // signing data content = ( - + {intl.formatMessage(signTxMessages.signMessage)} { p="16px" border="1px solid var(--yoroi-palette-gray-100)" borderRadius="6px" + id="signMessageBox-payload" >
{this.renderPayload(signData.payload)}
@@ -439,6 +441,7 @@ class SignTxPage extends Component { type="password" {...walletPasswordField.bind()} error={walletPasswordField.error} + id="walletPassword" />
@@ -486,6 +489,7 @@ class SignTxPage extends Component { color="primary" onClick={onCancel} disabled={isSubmitting} + id="cancelButton" > {intl.formatMessage(globalMessages.cancel)} @@ -496,6 +500,7 @@ class SignTxPage extends Component { disabled={(walletType === 'web' && !walletPasswordField.isValid) || isSubmitting} onClick={this.submit.bind(this)} sx={{ minWidth: 0 }} + id="confirmButton" > {intl.formatMessage(confirmButtonLabel)} diff --git a/packages/yoroi-extension/app/connector/components/signin/cardano/SignTx.js b/packages/yoroi-extension/app/connector/components/signin/cardano/SignTx.js index 67340343d2..d612cb6081 100644 --- a/packages/yoroi-extension/app/connector/components/signin/cardano/SignTx.js +++ b/packages/yoroi-extension/app/connector/components/signin/cardano/SignTx.js @@ -57,12 +57,12 @@ function CardanoSignTx({ renderExplorerHashLink={renderExplorerHashLink} txAssetsData={txAssetsData} /> - - + + {intl.formatMessage(signTxMessages.transactionFee)} - + {total.fee} {total.ticker} @@ -168,7 +168,7 @@ const ExpandableAssetsPanel = ({ }; const AsseetValueDisplay = ({ children }): Node => ( - + {children} diff --git a/packages/yoroi-extension/app/connector/components/signin/cardano/SignTxSummary.js b/packages/yoroi-extension/app/connector/components/signin/cardano/SignTxSummary.js index 8a4d8098df..4710b5a5f3 100644 --- a/packages/yoroi-extension/app/connector/components/signin/cardano/SignTxSummary.js +++ b/packages/yoroi-extension/app/connector/components/signin/cardano/SignTxSummary.js @@ -81,11 +81,11 @@ function CardanoSignTxSummary({ color="var(--yoroi-palette-common-white)" sx={{ background: 'linear-gradient(30.09deg, #244ABF 0%, #4760FF 176.73%)' }} > - + {intl.formatMessage(signTxMessages.summary)} - + {showOnlyTxFee ? total.fee : total.total} {total.ticker} diff --git a/packages/yoroi-extension/app/connector/components/signin/cardano/UtxoDetails.js b/packages/yoroi-extension/app/connector/components/signin/cardano/UtxoDetails.js index d1f586a5de..4da56b7b8a 100644 --- a/packages/yoroi-extension/app/connector/components/signin/cardano/UtxoDetails.js +++ b/packages/yoroi-extension/app/connector/components/signin/cardano/UtxoDetails.js @@ -117,7 +117,7 @@ class CardanoUtxoDetails extends Component { `${request.kind}-${request.address.address}-${request.addressIndex}-${identifier}`; const renderAmount = entry => { return ( -
+
{this.renderAmountDisplay({ entry: { ...entry, @@ -141,6 +141,7 @@ class CardanoUtxoDetails extends Component { justifyContent="space-between" py="16px" borderRadius="8px" + id="addressRow" > { {intl.formatMessage(connectorMessages.yourAddresses)} - + {txData.inputs.map((address, addressIndex) => { return this.renderRow({ kind: 'in', @@ -223,7 +224,7 @@ class CardanoUtxoDetails extends Component { {intl.formatMessage(connectorMessages.foreignAddresses)} - + {txData.foreignInputs.map((address, addressIndex) => { return this.renderRow({ kind: 'in-foreign', @@ -249,7 +250,7 @@ class CardanoUtxoDetails extends Component { {intl.formatMessage(connectorMessages.yourAddresses)} - + {txData.outputs .filter(o => !o.isForeign) .map((address, addressIndex) => { @@ -265,7 +266,7 @@ class CardanoUtxoDetails extends Component { {foreignOutputs.length > 0 && ( <> - + {intl.formatMessage(connectorMessages.foreignAddresses)} diff --git a/packages/yoroi-extension/app/containers/SidebarContainer.js b/packages/yoroi-extension/app/containers/SidebarContainer.js index eeaa2475bc..ef8411e678 100644 --- a/packages/yoroi-extension/app/containers/SidebarContainer.js +++ b/packages/yoroi-extension/app/containers/SidebarContainer.js @@ -16,6 +16,7 @@ export type GeneratedData = typeof SidebarContainer.prototype.generated; type Props = {| ...InjectedOrGenerated, + +onLogoClick?: void => void, |}; type InjectedProps = {| +selectedLayout: string, @@ -29,9 +30,16 @@ class SidebarContainer extends Component { await this.generated.actions.profile.toggleSidebar.trigger(); }; + static defaultProps: {| + onLogoClick: void, + |} = { + onLogoClick: undefined, + }; + render(): Node { const { stores, actions } = this.generated; const { profile } = stores; + const { onLogoClick } = this.props; const SidebarComponent = ( { route: category.route, }); }} - isActiveCategory={category => - stores.app.currentRoute.startsWith(category.route) - } + isActiveCategory={category => stores.app.currentRoute.startsWith(category.route)} categories={allCategories.filter(category => category.isVisible({ hasAnyWallets: stores.wallets.hasAnyWallets, @@ -57,6 +63,7 @@ class SidebarContainer extends Component { const SidebarRevampComponent = ( { actions.router.goToRoute.trigger({ route: category.route, @@ -130,7 +137,7 @@ class SidebarContainer extends Component { hasAnyWallets: stores.wallets.hasAnyWallets, }, delegation: { - getDelegationRequests: stores.delegation.getDelegationRequests + getDelegationRequests: stores.delegation.getDelegationRequests, }, }, actions: { diff --git a/packages/yoroi-extension/app/containers/banners/BannerContainer.js b/packages/yoroi-extension/app/containers/banners/BannerContainer.js index 3d9bac311e..0cbc521722 100644 --- a/packages/yoroi-extension/app/containers/banners/BannerContainer.js +++ b/packages/yoroi-extension/app/containers/banners/BannerContainer.js @@ -27,13 +27,11 @@ export default class BannerContainer extends Component isErgo(w.getParent().getNetworkInfo())) ?? false; const deprecationBanner = this.getDeprecationBanner(); return ( @@ -47,7 +45,7 @@ export default class BannerContainer extends Component )} - + {!environment.isProduction() && } {deprecationBanner} @@ -88,7 +86,10 @@ export default class BannerContainer extends Component |}, + wallets: {| + publicDerivers?: Array>, + selected: null | PublicDeriver<>, + |}, |}, actions: {||}, |} { @@ -109,6 +110,7 @@ export default class BannerContainer extends Component - |}, + wallets: { + selected: null | PublicDeriver<>, + ... + }, tokenInfoStore: {| tokenInfo: TokenInfoMap, |}, diff --git a/packages/yoroi-extension/app/containers/wallet/AddWalletPage.js b/packages/yoroi-extension/app/containers/wallet/AddWalletPage.js index 3da3078205..2c60892104 100644 --- a/packages/yoroi-extension/app/containers/wallet/AddWalletPage.js +++ b/packages/yoroi-extension/app/containers/wallet/AddWalletPage.js @@ -349,6 +349,8 @@ class AddWalletPage extends Component { onHardwareConnect={() => this.openDialogWrapper(WalletConnectHWOptionDialog)} onCreate={() => goToRoute.trigger({ route: ROUTES.WALLETS.CREATE_NEW_WALLET })} onRestore={() => goToRoute.trigger({ route: ROUTES.WALLETS.RESTORE_WALLET })} + goToCurrentWallet={() => goToRoute.trigger({ route: ROUTES.WALLETS.TRANSACTIONS })} + hasAnyWallets={hasAnyWallets} /> {activeDialog} diff --git a/packages/yoroi-extension/app/containers/wallet/AddWalletPageRevamp.js b/packages/yoroi-extension/app/containers/wallet/AddWalletPageRevamp.js index 611e0c02eb..15a826176d 100644 --- a/packages/yoroi-extension/app/containers/wallet/AddWalletPageRevamp.js +++ b/packages/yoroi-extension/app/containers/wallet/AddWalletPageRevamp.js @@ -8,17 +8,22 @@ type Props = {| +onCreate: void => void, +onRestore: void => void, +onHardwareConnect: void => void, + +goToCurrentWallet: void => void, + +hasAnyWallets: boolean, |}; export default function AddWalletPageRevamp(props: Props): Node { return ( - + - ) -} \ No newline at end of file + ); +} diff --git a/packages/yoroi-extension/app/containers/wallet/CreateWalletPageContainer.js b/packages/yoroi-extension/app/containers/wallet/CreateWalletPageContainer.js index b0cf2a1971..f0cf188720 100644 --- a/packages/yoroi-extension/app/containers/wallet/CreateWalletPageContainer.js +++ b/packages/yoroi-extension/app/containers/wallet/CreateWalletPageContainer.js @@ -11,6 +11,7 @@ import type { GeneratedData as SidebarContainerData } from '../SidebarContainer' import type { InjectedOrGenerated } from '../../types/injectedPropsType'; import type { NetworkRow } from '../../api/ada/lib/storage/database/primitives/tables'; import { PublicDeriver } from '../../api/ada/lib/storage/models/PublicDeriver'; +import { ROUTES } from '../../routes-config'; export const CreateWalletPagePromise: void => Promise = () => import('../../components/wallet/create-wallet/CreateWalletPage'); @@ -27,7 +28,12 @@ export default class CreateWalletPageContainer extends Component { return ( } - sidebar={} + sidebar={ + actions.router.goToRoute.trigger({ route: ROUTES.WALLETS.ADD })} + /> + } bgcolor="common.white" > diff --git a/packages/yoroi-extension/app/containers/wallet/TokensPageRevamp.js b/packages/yoroi-extension/app/containers/wallet/TokensPageRevamp.js index 9d2d7e3866..20d264148a 100644 --- a/packages/yoroi-extension/app/containers/wallet/TokensPageRevamp.js +++ b/packages/yoroi-extension/app/containers/wallet/TokensPageRevamp.js @@ -4,12 +4,11 @@ import { Component } from 'react'; import type { InjectedOrGenerated } from '../../types/injectedPropsType'; import type { Node } from 'react'; import { - genFormatTokenAmount, genLookupOrFail, getTokenIdentifierIfExists, getTokenStrictName, } from '../../stores/stateless/tokenHelpers'; -import { truncateToken } from '../../utils/formatters'; +import { splitAmount, truncateToken } from '../../utils/formatters'; import { computed } from 'mobx'; import type { TokenInfoMap } from '../../stores/toplevel/TokenInfoStore'; import type { TokenRow } from '../../api/ada/lib/storage/database/primitives/tables'; @@ -40,11 +39,21 @@ export default class TokensPageRevamp extends Component item.info.IsNFT === false) - .map(token => ({ - name: truncateToken(getTokenStrictName(token.info) ?? '-'), - id: getTokenIdentifierIfExists(token.info) ?? '-', - amount: genFormatTokenAmount(getTokenInfo)(token.entry), - })); + .map(token => { + const numberOfDecimals = token.info?.Metadata.numberOfDecimals ?? 0; + const shiftedAmount = token.entry.amount.shiftedBy(-numberOfDecimals); + const [beforeDecimal, afterDecimal] = splitAmount( + shiftedAmount, + numberOfDecimals + ); + + return { + name: truncateToken(getTokenStrictName(token.info) ?? '-'), + id: getTokenIdentifierIfExists(token.info) ?? '-', + amount: [beforeDecimal, afterDecimal].join(''), + amountForSorting: shiftedAmount, + } + }); })(); const txRequests = this.generated.stores.transactions.getTxRequests(publicDeriver); diff --git a/packages/yoroi-extension/app/containers/wallet/WalletAssetsPage.js b/packages/yoroi-extension/app/containers/wallet/WalletAssetsPage.js index 2219070727..7f19a04803 100644 --- a/packages/yoroi-extension/app/containers/wallet/WalletAssetsPage.js +++ b/packages/yoroi-extension/app/containers/wallet/WalletAssetsPage.js @@ -10,8 +10,8 @@ import { } from '../../api/common/lib/MultiToken'; import type { TokenInfoMap } from '../../stores/toplevel/TokenInfoStore'; import type { TokenRow } from '../../api/ada/lib/storage/database/primitives/tables'; -import { genFormatTokenAmount, genLookupOrFail, getTokenIdentifierIfExists, getTokenStrictName } from '../../stores/stateless/tokenHelpers'; -import { truncateToken } from '../../utils/formatters'; +import { genLookupOrFail, getTokenIdentifierIfExists, getTokenStrictName } from '../../stores/stateless/tokenHelpers'; +import { splitAmount, truncateToken } from '../../utils/formatters'; import AssetsPage from '../../components/wallet/assets/AssetsPage'; import type { TxRequests } from '../../stores/toplevel/TransactionsStore'; @@ -36,11 +36,20 @@ export default class WalletAssetsPage extends Component ({ entry, info: getTokenInfo(entry), - })).map(token => ({ - name: truncateToken(getTokenStrictName(token.info) ?? '-'), - id: (getTokenIdentifierIfExists(token.info) ?? '-'), - amount: genFormatTokenAmount(getTokenInfo)(token.entry), - })); + })).map(token => { + const numberOfDecimals = token.info?.Metadata.numberOfDecimals ?? 0; + const shiftedAmount = token.entry.amount.shiftedBy(-numberOfDecimals); + const [beforeDecimal, afterDecimal] = splitAmount( + shiftedAmount, + numberOfDecimals + ); + return { + name: truncateToken(getTokenStrictName(token.info) ?? '-'), + id: (getTokenIdentifierIfExists(token.info) ?? '-'), + amount: [beforeDecimal, afterDecimal].join(''), + amountForSorting: shiftedAmount, + } + }); })(); const txRequests = this.generated.stores.transactions.getTxRequests(publicDeriver); diff --git a/packages/yoroi-extension/app/containers/wallet/WalletSendPage.js b/packages/yoroi-extension/app/containers/wallet/WalletSendPage.js index 4c6c33e8bc..678ca53f68 100644 --- a/packages/yoroi-extension/app/containers/wallet/WalletSendPage.js +++ b/packages/yoroi-extension/app/containers/wallet/WalletSendPage.js @@ -12,13 +12,14 @@ import WalletSendFormRevamp from '../../components/wallet/send/WalletSendFormRev // Web Wallet Confirmation import WalletSendConfirmationDialogContainer from './dialogs/WalletSendConfirmationDialogContainer'; -import type { - GeneratedData as WalletSendConfirmationDialogContainerData -} from './dialogs/WalletSendConfirmationDialogContainer'; +import type { GeneratedData as WalletSendConfirmationDialogContainerData } from './dialogs/WalletSendConfirmationDialogContainer'; import WalletSendConfirmationDialog from '../../components/wallet/send/WalletSendConfirmationDialog'; import MemoNoExternalStorageDialog from '../../components/wallet/memos/MemoNoExternalStorageDialog'; import { WalletTypeOption } from '../../api/ada/lib/storage/models/ConceptualWallet/interfaces'; -import { isLedgerNanoWallet, isTrezorTWallet } from '../../api/ada/lib/storage/models/ConceptualWallet/index'; +import { + isLedgerNanoWallet, + isTrezorTWallet, +} from '../../api/ada/lib/storage/models/ConceptualWallet/index'; import { HaskellShelleyTxSignRequest } from '../../api/ada/transactions/shelley/HaskellShelleyTxSignRequest'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import type { SendUsingLedgerParams } from '../../actions/ada/ledger-send-actions'; @@ -29,12 +30,10 @@ import { SelectedExplorer } from '../../domain/SelectedExplorer'; import type { UnitOfAccountSettingType } from '../../types/unitOfAccountType'; import LocalizableError from '../../i18n/LocalizableError'; import type { ISignRequest } from '../../api/common/lib/transactions/ISignRequest'; -import { ApiOptions, getApiForNetwork, } from '../../api/common/utils'; +import { ApiOptions, getApiForNetwork } from '../../api/common/utils'; import { validateAmount, getMinimumValue } from '../../utils/validations'; import { addressToDisplayString } from '../../api/ada/lib/storage/bridge/utils'; -import { - MultiToken, -} from '../../api/common/lib/MultiToken'; +import { MultiToken } from '../../api/common/lib/MultiToken'; import type { TokenInfoMap } from '../../stores/toplevel/TokenInfoStore'; import type { TokenRow } from '../../api/ada/lib/storage/database/primitives/tables'; import { genLookupOrFail } from '../../stores/stateless/tokenHelpers'; @@ -54,7 +53,8 @@ import { trackSend } from '../../api/analytics'; const messages = defineMessages({ txConfirmationLedgerNanoLine1: { id: 'wallet.send.ledger.confirmationDialog.info.line.1', - defaultMessage: '!!!After connecting your Ledger device to your computer’s USB port, press the Send using Ledger button.', + defaultMessage: + '!!!After connecting your Ledger device to your computer’s USB port, press the Send using Ledger button.', }, sendUsingLedgerNano: { id: 'wallet.send.ledger.confirmationDialog.submit', @@ -62,7 +62,8 @@ const messages = defineMessages({ }, txConfirmationTrezorTLine1: { id: 'wallet.send.trezor.confirmationDialog.info.line.1', - defaultMessage: '!!!After connecting your Trezor device to your computer, press the Send using Trezor button.', + defaultMessage: + '!!!After connecting your Trezor device to your computer, press the Send using Trezor button.', }, sendUsingTrezorT: { id: 'wallet.send.trezor.confirmationDialog.submit', @@ -83,24 +84,22 @@ type AllProps = {| ...Props, ...InjectedProps |}; @observer class WalletSendPage extends Component { - - static contextTypes: {|intl: $npm$ReactIntl$IntlFormat|} = { + static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; @observable showMemo: boolean = false; - closeTransactionSuccessDialog: void => void = () => { this.generated.actions.dialogs.closeActiveDialog.trigger(); this.generated.actions.router.goToRoute.trigger({ route: ROUTES.WALLETS.TRANSACTIONS }); - } + }; openTransactionSuccessDialog: void => void = () => { this.generated.actions.dialogs.push.trigger({ - dialog: TransactionSuccessDialog + dialog: TransactionSuccessDialog, }); - } + }; componentDidMount(): void { runInAction(() => { @@ -114,12 +113,12 @@ class WalletSendPage extends Component { this.generated.actions.memos.closeMemoDialog.trigger(); }; - openDialog: any => void = (dialog) => { - this.generated.actions.dialogs.closeActiveDialog.trigger() + openDialog: any => void = dialog => { + this.generated.actions.dialogs.closeActiveDialog.trigger(); this.generated.actions.dialogs.push.trigger({ dialog, }); - } + }; _getNumDecimals(): number { const publicDeriver = this.generated.stores.wallets.selected; @@ -127,7 +126,7 @@ class WalletSendPage extends Component { const defaultToken = this.generated.stores.tokenInfoStore.getDefaultTokenInfo( publicDeriver.getParent().getNetworkInfo().NetworkId ); - const getTokenInfo = genLookupOrFail(this.generated.stores.tokenInfoStore.tokenInfo) + const getTokenInfo = genLookupOrFail(this.generated.stores.tokenInfoStore.tokenInfo); const info = getTokenInfo({ identifier: defaultToken.Identifier, networkId: defaultToken.NetworkId, @@ -142,29 +141,29 @@ class WalletSendPage extends Component { const { transactionBuilderStore } = this.generated.stores; - const { uiDialogs, profile, } = this.generated.stores; + const { uiDialogs, profile } = this.generated.stores; const { actions } = this.generated; const { hasAnyPending } = this.generated.stores.transactions; const { txBuilderActions } = this.generated.actions; // disallow sending when pending tx exists if ( - ( - uiDialogs.isOpen(HWSendConfirmationDialog) || - uiDialogs.isOpen(WalletSendConfirmationDialog) - ) && hasAnyPending + (uiDialogs.isOpen(HWSendConfirmationDialog) || + uiDialogs.isOpen(WalletSendConfirmationDialog)) && + hasAnyPending ) { actions.dialogs.closeActiveDialog.trigger(); } const walletType = publicDeriver.getParent().getWalletType(); - const targetDialog = walletType === WalletTypeOption.HARDWARE_WALLET ? - HWSendConfirmationDialog : - WalletSendConfirmationDialog; + const targetDialog = + walletType === WalletTypeOption.HARDWARE_WALLET + ? HWSendConfirmationDialog + : WalletSendConfirmationDialog; const onSubmit = () => { actions.dialogs.push.trigger({ - dialog: targetDialog + dialog: targetDialog, }); txBuilderActions.updateTentativeTx.trigger(); }; @@ -198,10 +197,12 @@ class WalletSendPage extends Component { uriParams={this.generated.stores.loading.uriParams} resetUriParams={this.generated.stores.loading.resetUriParams} showMemo={this.showMemo} - onAddMemo={() => this.showMemoDialog({ - dialog: MemoNoExternalStorageDialog, - continuation: this.toggleShowMemo, - })} + onAddMemo={() => + this.showMemoDialog({ + dialog: MemoNoExternalStorageDialog, + continuation: this.toggleShowMemo, + }) + } spendableBalance={this.generated.stores.transactions.getBalanceRequest.result} onAddToken={txBuilderActions.addToken.trigger} onRemoveTokens={txBuilderActions.removeTokens.trigger} @@ -225,15 +226,17 @@ class WalletSendPage extends Component { <> validateAmount( - amount, - transactionBuilderStore.selectedToken ?? defaultToken, - getMinimumValue( - publicDeriver.getParent().getNetworkInfo(), - transactionBuilderStore.selectedToken?.IsDefault ?? true - ), - this.context.intl, - )} + validateAmount={amount => + validateAmount( + amount, + transactionBuilderStore.selectedToken ?? defaultToken, + getMinimumValue( + publicDeriver.getParent().getNetworkInfo(), + transactionBuilderStore.selectedToken?.IsDefault ?? true + ), + this.context.intl + ) + } defaultToken={defaultToken} getTokenInfo={genLookupOrFail(this.generated.stores.tokenInfoStore.tokenInfo)} onSubmit={onSubmit} @@ -252,10 +255,12 @@ class WalletSendPage extends Component { uriParams={this.generated.stores.loading.uriParams} resetUriParams={this.generated.stores.loading.resetUriParams} showMemo={this.showMemo} - onAddMemo={() => this.showMemoDialog({ - dialog: MemoNoExternalStorageDialog, - continuation: this.toggleShowMemo, - })} + onAddMemo={() => + this.showMemoDialog({ + dialog: MemoNoExternalStorageDialog, + continuation: this.toggleShowMemo, + }) + } spendableBalance={this.generated.stores.transactions.getBalanceRequest.result} onAddToken={txBuilderActions.addToken.trigger} selectedToken={transactionBuilderStore.selectedToken} @@ -265,7 +270,7 @@ class WalletSendPage extends Component { ); } - renderDialog: (() => Node) = () => { + renderDialog: () => Node = () => { const { uiDialogs } = this.generated.stores; if (uiDialogs.isOpen(WalletSendConfirmationDialog)) { @@ -277,29 +282,32 @@ class WalletSendPage extends Component { if (uiDialogs.isOpen(MemoNoExternalStorageDialog)) { return this.noCloudWarningDialog(); } - if(uiDialogs.isOpen(TransactionSuccessDialog)){ - return () + if (uiDialogs.isOpen(TransactionSuccessDialog)) { + return ( + + ); } if (uiDialogs.isOpen(AddNFTDialog)) { - return this.renderNFTDialog() + return this.renderNFTDialog(); } if (uiDialogs.isOpen(AddTokenDialog)) { - return this.renderAddTokenDialog() + return this.renderAddTokenDialog(); } return ''; - } + }; /** Web Wallet Send Confirmation dialog - * Callback that creates a container to avoid the component knowing about actions/stores */ - webWalletDoConfirmation: (() => Node) = () => { + * Callback that creates a container to avoid the component knowing about actions/stores */ + webWalletDoConfirmation: () => Node = () => { const publicDeriver = this.generated.stores.wallets.selected; - if (!publicDeriver) throw new Error(`Active wallet required for ${nameof(this.webWalletDoConfirmation)}.`); + if (!publicDeriver) + throw new Error(`Active wallet required for ${nameof(this.webWalletDoConfirmation)}.`); const { transactionBuilderStore } = this.generated.stores; if (!transactionBuilderStore.tentativeTx) { @@ -307,18 +315,21 @@ class WalletSendPage extends Component { } const signRequest = transactionBuilderStore.tentativeTx; - return (); + return ( + + ); }; - renderTxPreviewStep: (() => Node) = () => { + renderTxPreviewStep: () => Node = () => { const publicDeriver = this.generated.stores.wallets.selected; - if (!publicDeriver) throw new Error(`Active wallet required for ${nameof(this.webWalletDoConfirmation)}.`); + if (!publicDeriver) + throw new Error(`Active wallet required for ${nameof(this.webWalletDoConfirmation)}.`); const { transactionBuilderStore } = this.generated.stores; if (!transactionBuilderStore.tentativeTx) { @@ -326,25 +337,27 @@ class WalletSendPage extends Component { } const signRequest = transactionBuilderStore.tentativeTx; - return (); + return ( + + ); }; - /** Hardware Wallet (Trezor or Ledger) Confirmation dialog - * Callback that creates a component to avoid the component knowing about actions/stores - * separate container is not needed, this container acts as container for Confirmation dialog */ - hardwareWalletDoConfirmation: (() => Node) = () => { + * Callback that creates a component to avoid the component knowing about actions/stores + * separate container is not needed, this container acts as container for Confirmation dialog */ + hardwareWalletDoConfirmation: () => Node = () => { const publicDeriver = this.generated.stores.wallets.selected; - if (!publicDeriver) throw new Error(`Active wallet required for ${nameof(this.webWalletDoConfirmation)}.`); + if (!publicDeriver) + throw new Error(`Active wallet required for ${nameof(this.webWalletDoConfirmation)}.`); const selectedApiType = getApiForNetwork(publicDeriver.getParent().getNetworkInfo()); if (selectedApiType !== ApiOptions.ada) { @@ -369,11 +382,17 @@ class WalletSendPage extends Component { let hwSendConfirmationDialog: Node = null; if (!(signRequest instanceof HaskellShelleyTxSignRequest)) { - throw new Error(`${nameof(this.hardwareWalletDoConfirmation)} hw wallets only supported for Byron`); + throw new Error( + `${nameof(this.hardwareWalletDoConfirmation)} hw wallets only supported for Byron` + ); } - const selectedExplorerForNetwork = this.generated.stores.explorers.selectedExplorer - .get(publicDeriver.getParent().getNetworkInfo().NetworkId) - ?? (() => { throw new Error('No explorer for wallet network'); })(); + const selectedExplorerForNetwork = + this.generated.stores.explorers.selectedExplorer.get( + publicDeriver.getParent().getNetworkInfo().NetworkId + ) ?? + (() => { + throw new Error('No explorer for wallet network'); + })(); if (isLedgerNanoWallet(conceptualWallet)) { const messagesLedgerNano = { @@ -397,22 +416,21 @@ class WalletSendPage extends Component { messages={messagesLedgerNano} isSubmitting={ledgerSendStore.isActionProcessing} error={ledgerSendStore.error} - onSubmit={ - () => { - ledgerSendAction.sendUsingLedgerWallet.trigger({ - params: { signRequest }, - publicDeriver, - onSuccess: this.openTransactionSuccessDialog, - }); - trackSend(); - } - } + onSubmit={() => { + ledgerSendAction.sendUsingLedgerWallet.trigger({ + params: { signRequest }, + publicDeriver, + onSuccess: this.openTransactionSuccessDialog, + }); + trackSend(); + }} onCancel={ledgerSendAction.cancel.trigger} unitOfAccountSetting={this.generated.stores.profile.unitOfAccount} - addressToDisplayString={ - addr => addressToDisplayString(addr, publicDeriver.getParent().getNetworkInfo()) + addressToDisplayString={addr => + addressToDisplayString(addr, publicDeriver.getParent().getNetworkInfo()) } - />); + /> + ); } else if (isTrezorTWallet(conceptualWallet)) { const messagesTrezor = { infoLine1: messages.txConfirmationTrezorTLine1, @@ -434,22 +452,21 @@ class WalletSendPage extends Component { messages={messagesTrezor} isSubmitting={trezorSendStore.isActionProcessing} error={trezorSendStore.error} - onSubmit={ - () => { - trezorSendAction.sendUsingTrezor.trigger({ - params: { signRequest }, - publicDeriver, - onSuccess: this.openTransactionSuccessDialog, - }) - trackSend(); - } - } + onSubmit={() => { + trezorSendAction.sendUsingTrezor.trigger({ + params: { signRequest }, + publicDeriver, + onSuccess: this.openTransactionSuccessDialog, + }); + trackSend(); + }} onCancel={trezorSendAction.cancel.trigger} unitOfAccountSetting={this.generated.stores.profile.unitOfAccount} - addressToDisplayString={ - addr => addressToDisplayString(addr, publicDeriver.getParent().getNetworkInfo()) + addressToDisplayString={addr => + addressToDisplayString(addr, publicDeriver.getParent().getNetworkInfo()) } - />); + /> + ); } else { throw new Error('Unsupported hardware wallet found at hardwareWalletDoConfirmation.'); } @@ -457,10 +474,10 @@ class WalletSendPage extends Component { return hwSendConfirmationDialog; }; - showMemoDialog: {| + showMemoDialog: ({| continuation: void => void, dialog: any, - |} => void = (request) => { + |}) => void = request => { if (this.generated.stores.memos.hasSetSelectedExternalStorageProvider) { return request.continuation(); } @@ -471,35 +488,43 @@ class WalletSendPage extends Component { continuation: request.continuation, }, }); - } + }; noCloudWarningDialog: void => Node = () => { - const { actions, } = this.generated; - return ( { - actions.memos.closeMemoDialog.trigger(); - actions.router.goToRoute.trigger({ route: ROUTES.SETTINGS.EXTERNAL_STORAGE }); - }} - onAcknowledge={() => { - this.generated.stores.uiDialogs.getParam void>('continuation')(); - }} - />); - } + const { actions } = this.generated; + return ( + { + actions.memos.closeMemoDialog.trigger(); + actions.router.goToRoute.trigger({ route: ROUTES.SETTINGS.EXTERNAL_STORAGE }); + }} + onAcknowledge={() => { + this.generated.stores.uiDialogs.getParam<(void) => void>('continuation')(); + }} + /> + ); + }; - calculateMinAda: Array<{| - token: $ReadOnly, included: boolean - |}> => string = (selectedTokens) => { + calculateMinAda: ( + Array<{| + token: $ReadOnly, + included: boolean, + |}> + ) => string = selectedTokens => { const { transactionBuilderStore } = this.generated.stores; - const { calculateMinAda } = transactionBuilderStore; + const { calculateMinAda } = transactionBuilderStore; const tokens = this._mergeTokens(selectedTokens); const minAdaAmount = calculateMinAda(tokens.map(token => ({ token }))); - return (new BigNumber(minAdaAmount)).shiftedBy(-this._getNumDecimals()).toString() - } + return new BigNumber(minAdaAmount).shiftedBy(-this._getNumDecimals()).toString(); + }; - _mergeTokens: Array<{| - token: $ReadOnly, included: boolean - |}> => Array<$ReadOnly> = (selectedTokens) => { + _mergeTokens: ( + Array<{| + token: $ReadOnly, + included: boolean, + |}> + ) => Array<$ReadOnly> = selectedTokens => { const { transactionBuilderStore } = this.generated.stores; const { plannedTxInfoMap } = transactionBuilderStore; const tokens = new Map>(); @@ -515,22 +540,21 @@ class WalletSendPage extends Component { }); plannedTxInfoMap.forEach(entry => { const id = entry.token.Identifier; - if (!shouldNotInclude.has(id)) - tokens.set(id, entry.token); + if (!shouldNotInclude.has(id)) tokens.set(id, entry.token); }); - return [...tokens.values()] - } + return [...tokens.values()]; + }; - shouldAddMoreTokens: Array<{| token: $ReadOnly, included: boolean |}> => boolean = ( - tokens - ) => { + shouldAddMoreTokens: ( + Array<{| token: $ReadOnly, included: boolean |}> + ) => boolean = tokens => { const { maxAssetsAllowed } = this.generated.stores.transactionBuilderStore; const allTokens = this._mergeTokens(tokens); return allTokens.length <= maxAssetsAllowed; - } + }; renderNFTDialog: void => Node = () => { const publicDeriver = this.generated.stores.wallets.selected; @@ -553,8 +577,8 @@ class WalletSendPage extends Component { plannedTxInfoMap={transactionBuilderStore.plannedTxInfoMap} shouldAddMoreTokens={this.shouldAddMoreTokens} /> - ) - } + ); + }; renderAddTokenDialog: void => Node = () => { const publicDeriver = this.generated.stores.wallets.selected; @@ -579,12 +603,11 @@ class WalletSendPage extends Component { plannedTxInfoMap={transactionBuilderStore.plannedTxInfoMap} selectedNetwork={publicDeriver.getParent().getNetworkInfo()} /> - ) - } + ); + }; @computed get generated(): {| - WalletSendConfirmationDialogContainerProps: - InjectedOrGenerated, + WalletSendConfirmationDialogContainerProps: InjectedOrGenerated, actions: {| ada: {| ledgerSend: {| @@ -595,8 +618,8 @@ class WalletSendPage extends Component { params: SendUsingLedgerParams, publicDeriver: PublicDeriver<>, onSuccess?: void => void, - |}) => Promise - |} + |}) => Promise, + |}, |}, trezorSend: {| cancel: {| trigger: (params: void) => void |}, @@ -605,8 +628,8 @@ class WalletSendPage extends Component { params: SendUsingTrezorParams, publicDeriver: PublicDeriver<>, onSuccess?: void => void, - |}) => Promise - |} + |}) => Promise, + |}, |}, |}, txBuilderActions: {| @@ -614,71 +637,71 @@ class WalletSendPage extends Component { trigger: (params: void) => Promise, |}, reset: {| - trigger: (params: void) => void + trigger: (params: void) => void, |}, updateSendAllStatus: {| - trigger: (params: boolean | void) => void + trigger: (params: boolean | void) => void, |}, updateAmount: {| - trigger: (params: ?BigNumber) => void + trigger: (params: ?BigNumber) => void, |}, addToken: {| trigger: (params: {| token?: $ReadOnly, shouldReset?: boolean, - |}) => void + |}) => void, |}, deselectToken: {| - trigger: void => void + trigger: void => void, |}, removeTokens: {| trigger: (params: Array<$ReadOnly>) => void, |}, updateMemo: {| - trigger: (params: void | string) => void + trigger: (params: void | string) => void, |}, updateReceiver: {| - trigger: (params: void | string) => void + trigger: (params: void | string) => void, |}, updateTentativeTx: {| - trigger: (params: void) => void - |} + trigger: (params: void) => void, + |}, |}, dialogs: {| closeActiveDialog: {| - trigger: (params: void) => void + trigger: (params: void) => void, |}, push: {| trigger: (params: {| dialog: any, - params?: any - |}) => void + params?: any, + |}) => void, |}, |}, memos: {| - closeMemoDialog: {| trigger: (params: void) => void |} + closeMemoDialog: {| trigger: (params: void) => void |}, |}, router: {| goToRoute: {| trigger: (params: {| publicDeriver?: null | PublicDeriver<>, params?: ?any, - route: string - |}) => void - |} - |} + route: string, + |}) => void, + |}, + |}, |}, initialShowMemoState: boolean, stores: {| coinPriceStore: {| - getCurrentPrice: (from: string, to: string) => ?string + getCurrentPrice: (from: string, to: string) => ?string, |}, loading: {| resetUriParams: void => void, - uriParams: ?UriParams + uriParams: ?UriParams, |}, memos: {| - hasSetSelectedExternalStorageProvider: boolean + hasSetSelectedExternalStorageProvider: boolean, |}, explorers: {| selectedExplorer: Map, @@ -689,12 +712,12 @@ class WalletSendPage extends Component { |}, profile: {| isClassicTheme: boolean, - unitOfAccount: UnitOfAccountSettingType + unitOfAccount: UnitOfAccountSettingType, |}, transactionBuilderStore: {| createUnsignedTx: {| error: ?LocalizableError, - isExecuting: boolean + isExecuting: boolean, |}, fee: ?MultiToken, shouldSendAll: boolean, @@ -710,7 +733,7 @@ class WalletSendPage extends Component { shouldSendAll?: boolean, |}>, minAda: ?MultiToken, - calculateMinAda: Array<{| token: $ReadOnly |}> => string, + calculateMinAda: (Array<{| token: $ReadOnly |}>) => string, maxSendableAmount: {| error: ?LocalizableError, isExecuting: boolean, @@ -721,13 +744,13 @@ class WalletSendPage extends Component { ada: {| ledgerSend: {| error: ?LocalizableError, - isActionProcessing: boolean + isActionProcessing: boolean, |}, trezorSend: {| error: ?LocalizableError, - isActionProcessing: boolean - |} - |} + isActionProcessing: boolean, + |}, + |}, |}, transactions: {| hasAnyPending: boolean, @@ -737,11 +760,11 @@ class WalletSendPage extends Component { |}, uiDialogs: {| getParam: (number | string) => T, - isOpen: any => boolean + isOpen: any => boolean, |}, - wallets: {| selected: null | PublicDeriver<> |} - |} - |} { + wallets: {| selected: null | PublicDeriver<> |}, + |}, + |} { if (this.props.generated !== undefined) { return this.props.generated; } @@ -783,9 +806,10 @@ class WalletSendPage extends Component { transactions: { hasAnyPending: stores.transactions.hasAnyPending, getBalanceRequest: (() => { - if (stores.wallets.selected == null) return { - result: undefined, - }; + if (stores.wallets.selected == null) + return { + result: undefined, + }; const { requests } = stores.transactions.getTxRequests(stores.wallets.selected); return { @@ -840,7 +864,7 @@ class WalletSendPage extends Component { }, memos: { closeMemoDialog: { - trigger: actions.memos.closeMemoDialog.trigger + trigger: actions.memos.closeMemoDialog.trigger, }, }, txBuilderActions: { @@ -854,7 +878,7 @@ class WalletSendPage extends Component { reset: { trigger: actions.txBuilderActions.reset.trigger }, updateMemo: { trigger: actions.txBuilderActions.updateMemo.trigger }, calculateMaxAmount: { - trigger: actions.txBuilderActions.calculateMaxAmount.trigger + trigger: actions.txBuilderActions.calculateMaxAmount.trigger, }, }, ada: { @@ -862,7 +886,7 @@ class WalletSendPage extends Component { init: { trigger: actions.ada.ledgerSend.init.trigger }, cancel: { trigger: actions.ada.ledgerSend.cancel.trigger }, sendUsingLedgerWallet: { - trigger: actions.ada.ledgerSend.sendUsingLedgerWallet.trigger + trigger: actions.ada.ledgerSend.sendUsingLedgerWallet.trigger, }, }, trezorSend: { @@ -872,9 +896,10 @@ class WalletSendPage extends Component { }, }, initialShowMemoState: (false: boolean), - WalletSendConfirmationDialogContainerProps: ( - { actions, stores, }: InjectedOrGenerated - ), + WalletSendConfirmationDialogContainerProps: ({ + actions, + stores, + }: InjectedOrGenerated), }); } } diff --git a/packages/yoroi-extension/app/containers/wallet/restore/RestoreWalletPage.js b/packages/yoroi-extension/app/containers/wallet/restore/RestoreWalletPage.js index c57cbc4805..b07bcf8130 100644 --- a/packages/yoroi-extension/app/containers/wallet/restore/RestoreWalletPage.js +++ b/packages/yoroi-extension/app/containers/wallet/restore/RestoreWalletPage.js @@ -24,6 +24,7 @@ import TopBarLayout from '../../../components/layout/TopBarLayout'; import BannerContainer from '../../banners/BannerContainer'; import SidebarContainer from '../../SidebarContainer'; import LocalizableError from '../../../i18n/LocalizableError'; +import { ROUTES } from '../../../routes-config'; export const RestoreWalletPagePromise: void => Promise = () => import('../../../components/wallet/restore/RestoreWalletPage'); @@ -40,7 +41,12 @@ export default class RestoreWalletPage extends Component { return ( } - sidebar={} + sidebar={ + actions.router.goToRoute.trigger({ route: ROUTES.WALLETS.ADD })} + /> + } bgcolor="common.white" > 10 characters long.", "global.publicKey.explanation": "Public keys allow seeing the wallet history for the wallet, but does not allow to spend or move the funds in any way (private key is not included)", "global.receive": "Receive", @@ -462,6 +463,7 @@ "wallet.add.page.hw.tooltip": "Create or restore a Yoroi wallet
using a Ledger or Trezor hardware wallet.", "wallet.add.page.restore.title": "Restore wallet", "wallet.add.page.restore.tooltip": "Enter a 15-word recovery phrase
to restore an already-existing Yoroi wallet,
or import an existing Yoroi paper wallet.", + "wallet.add.page.revamp.backButtonLabel": "Back to current wallet", "wallet.add.page.revamp.connectHardwareWallet": "Connect hardware wallet", "wallet.add.page.revamp.createWallet": "Create new wallet", "wallet.add.page.revamp.restoreWallet": "Restore existing wallet", @@ -907,6 +909,7 @@ "wallet.staking.pool.unknownLabel": "Unknown pool", "wallet.staking.rewards.openRewardHistory": "Open Reward History", "wallet.staking.rewards.rewardHistory": "Reward History", + "wallet.staking.rewards.rewardHistory.epochNum": "Epoch {number}", "wallet.staking.summary": "Summary", "wallet.staking.warning.pendingTx": "You cannot change your delegation preference while a transaction is pending", "wallet.summary.no.transaction": "No transaction history.", @@ -972,9 +975,9 @@ "wallet.transaction.state.failed": "failed", "wallet.transaction.state.pending": "pending", "wallet.transaction.state.submitted": "submitted", - "wallet.transaction.success.button.label": "Transaction page", - "wallet.transaction.success.explanation": "Track the status of the transaction from the Transactions page", - "wallet.transaction.success.title": "Successfully sent", + "wallet.transaction.success.button.label": "Go To Transactions", + "wallet.transaction.success.explanation": "Check this transaction in the list of wallet transactions", + "wallet.transaction.success.title": "Transaction submitted", "wallet.transaction.transactionAmount": "Transaction amount", "wallet.transaction.transactionId": "Transaction ID", "wallet.transaction.transactionMetadata": "Transaction Metadata", diff --git a/packages/yoroi-extension/app/i18n/locales/hu-HU.json b/packages/yoroi-extension/app/i18n/locales/hu-HU.json index 7c0f4f349f..df622b5c49 100644 --- a/packages/yoroi-extension/app/i18n/locales/hu-HU.json +++ b/packages/yoroi-extension/app/i18n/locales/hu-HU.json @@ -65,6 +65,10 @@ "connector.connect.info": "Your connection preferences will be saved to your Yoroi dApp list.", "connector.connect.noWalletsFound": "Ooops, no {network} wallets found.", "connector.connect.noWebsitesConnected": "You don't have any websites connected yet", + "connector.connected-dapps.cardanoLabel": "Cardano, ADA", + "connector.connected-dapps.dappsLabel": "Dapps", + "connector.connected-dapps.ergoLabel": "Ergo, ERG", + "connector.connected-dapps.walletsLabel": "Wallets", "connector.foreignAddresses": "Foreign Addresses", "connector.from": "From (Inputs): {qty}", "connector.fromWallet": "From wallet", @@ -440,8 +444,6 @@ "wallet.add.optionDialog.connect.hw.ledger.title": "Ledger Hardware Wallet", "wallet.add.optionDialog.connect.hw.trezor.learnMoreText": "A Trezor hardware wallet is a small USB device that adds an extra level of security to your wallet. It is more secure because your private key never leaves the hardware wallet. This protects your funds even if your computer is compromised due to malware, phishing attempts, etc.", "wallet.add.optionDialog.connect.hw.trezor.title": "Trezor Hardware Wallet", - "wallet.add.optionDialog.create.normalWallet.description": "A standard wallet backed by a recovery phrase.", - "wallet.add.optionDialog.create.paperWallet.description": "Paper wallets can be created even on devices not connected to the internet which makes them well-suited for single-use cold storage.", "wallet.add.optionDialog.restore.dialogTitle": "Tárca helyreállítása", "wallet.add.optionDialog.restore.normalWallet.description": "If you have a recovery phrase consisting of {length} words, choose this option to restore your wallet.", "wallet.add.optionDialog.restore.normalWallet.title": "Enter a {length}-word recovery phrase", @@ -464,6 +466,7 @@ "wallet.add.page.revamp.createWallet": "Create new wallet", "wallet.add.page.revamp.restoreWallet": "Restore existing wallet", "wallet.add.page.revamp.subtitle": "Light wallet for Cardano assets", + "wallet.add.page.revamp.backButtonLabel": "Back to current wallet", "wallet.add.page.subtitle.label": "Yoroi light wallet for Cardano", "wallet.add.page.title": "Your gateway
to the
financial world", "wallet.address.category.addressBook": "Addresses that do not belong to you, but are relevant to your wallet", @@ -667,6 +670,7 @@ "wallet.hw.incorrectDevice": "Incorrect device detected. Expected device {expectedDeviceId}, but got device {responseDeviceId}. Please plug in the correct device", "wallet.hw.incorrectVersion": "Incorrect device version detected. We support version {supportedVersions} but you have version {responseVersion}.", "wallet.hw.ledger.app.not.running": "The Cardano App is not running on your Ledger", + "wallet.hw.ledger.catalyst.cip36.unsupported": "Catalyst registration requires Ledger app version 6.", "wallet.hw.ledger.catalyst.unsupported.106": "Please upgrade your Ledger firmware version to at least 2.0.0 and Caradano app version to 2.3.2 or above.", "wallet.hw.ledger.common.error.101": "Operation cancelled on Ledger device.", "wallet.hw.ledger.common.error.102": "Operation cancelled by user.", @@ -904,6 +908,7 @@ "wallet.staking.pool.unknownLabel": "Unknown pool", "wallet.staking.rewards.openRewardHistory": "Open Reward History", "wallet.staking.rewards.rewardHistory": "Reward History", + "wallet.staking.rewards.rewardHistory.epochNum": "Epoch {number}", "wallet.staking.summary": "Summary", "wallet.staking.warning.pendingTx": "You cannot change your delegation preference while a transaction is pending", "wallet.summary.no.transaction": "No transaction history.", @@ -969,9 +974,9 @@ "wallet.transaction.state.failed": "failed", "wallet.transaction.state.pending": "pending", "wallet.transaction.state.submitted": "submitted", - "wallet.transaction.success.button.label": "Transaction page", - "wallet.transaction.success.explanation": "Track the status of the transaction from the Transactions page", - "wallet.transaction.success.title": "Successfully sent", + "wallet.transaction.success.button.label": "Go To Transactions", + "wallet.transaction.success.explanation": "Check this transaction in the list of wallet transactions", + "wallet.transaction.success.title": "Transaction submitted", "wallet.transaction.transactionAmount": "Transaction amount", "wallet.transaction.transactionId": "Transaction ID", "wallet.transaction.transactionMetadata": "Transaction Metadata", @@ -1025,7 +1030,7 @@ "wallet.voting.dialog.title": "Register for Voting", "wallet.voting.dialog.transactionLabel": "Transaction", "wallet.voting.keepDelegated": "Your voting power is how much you delegate and the voting rewards will be distributed to your delegation reward address. Please keep delegated until the voting ends.", - "wallet.voting.ledgerNanoRequirement": "
Updatethe Cardano app on your Ledger to version 2.3.2 or above with Ledger Live.", + "wallet.voting.ledgerNanoRequirement": "Updatethe Cardano app on your Ledger to version 6 or above with Ledger Live.", "wallet.voting.line2": "Before you begin, make sure to complete steps below", "wallet.voting.line3": "Download the Catalyst Voting App.", "wallet.voting.line4": "Open the Catalyst Voting App and click on the Complete registration button.", @@ -1056,4 +1061,4 @@ "yoroiTransfer.waiting.progressInfo.checkingAddresses": "Checking addresses funds", "yoroiTransfer.waiting.progressInfo.restoringAddresses": "Fetching addresses", "yoroiTransfer.waiting.title.label": "Wallet is being restored" -} \ No newline at end of file +} diff --git a/packages/yoroi-extension/app/i18n/locales/vi-VN.json b/packages/yoroi-extension/app/i18n/locales/vi-VN.json index 506b907ea2..20595176d6 100644 --- a/packages/yoroi-extension/app/i18n/locales/vi-VN.json +++ b/packages/yoroi-extension/app/i18n/locales/vi-VN.json @@ -65,6 +65,10 @@ "connector.connect.info": "Tùy chọn kết nối của bạn sẽ được lưu vào danh sách dApp Yoroi.", "connector.connect.noWalletsFound": "Không có {network}.", "connector.connect.noWebsitesConnected": "Bạn chưa có bất kỳ trang web nào được kết nối", + "connector.connected-dapps.cardanoLabel": "Cardano, ADA", + "connector.connected-dapps.dappsLabel": "Dapps", + "connector.connected-dapps.ergoLabel": "Ergo, ERG", + "connector.connected-dapps.walletsLabel": "Các Ví", "connector.foreignAddresses": "Các địa chỉ bên ngoài", "connector.from": "Từ (đầu vào): {qty}", "connector.fromWallet": "Từ Ví", @@ -440,8 +444,6 @@ "wallet.add.optionDialog.connect.hw.ledger.title": "Ví cứng Ledger", "wallet.add.optionDialog.connect.hw.trezor.learnMoreText": "Ví cứng Trezor là một thiết bị USB nhỏ bổ sung thêm mức độ bảo mật cho ví của bạn. Nó an toàn hơn vì khóa riêng của bạn không bao giờ rời khỏi ví phần cứng. Điều này bảo vệ tiền của bạn ngay cả khi máy tính của bạn bị xâm phạm do phần mềm độc hại, nỗ lực lừa đảo, v. v.", "wallet.add.optionDialog.connect.hw.trezor.title": "Ví cứng Trezor", - "wallet.add.optionDialog.create.normalWallet.description": "Một ví tiêu chuẩn được hỗ trợ bởi một cụm từ khôi phục.", - "wallet.add.optionDialog.create.paperWallet.description": "Ví giấy có thể được tạo ngay cả trên các thiết bị không được kết nối với internet, điều này khiến chúng rất phù hợp để lưu trữ lạnh sử dụng một lần.", "wallet.add.optionDialog.restore.dialogTitle": "Khôi phục Ví", "wallet.add.optionDialog.restore.normalWallet.description": "Nếu bạn có một cụm từ khôi phục bao gồm {length} từ, hãy chọn tùy chọn này để khôi phục ví của bạn.", "wallet.add.optionDialog.restore.normalWallet.title": "Nhập {length}-từ trong cụm từ khôi phục", @@ -464,6 +466,7 @@ "wallet.add.page.revamp.createWallet": "Tạo ví mới", "wallet.add.page.revamp.restoreWallet": "Khôi phục ví đã tồn tại", "wallet.add.page.revamp.subtitle": "Ví nhẹ cho tài sản Cardano", + "wallet.add.page.revamp.backButtonLabel": "Back to current wallet", "wallet.add.page.subtitle.label": "Ví nhẹ Yoroi cho Cardano", "wallet.add.page.title": "Cửa ngõ
của bạn đến với thế giới tài chính
", "wallet.address.category.addressBook": "Địa chỉ không thuộc về bạn nhưng có liên quan đến ví của bạn", @@ -667,6 +670,7 @@ "wallet.hw.incorrectDevice": "Đã phát hiện thiết bị không chính xác. Cần có thiết bị {expectedDeviceId}, nhưng có thiết bị {responseDeviceId}. Vui lòng cắm đúng thiết bị", "wallet.hw.incorrectVersion": "Đã phát hiện phiên bản thiết bị không chính xác. Chúng tôi hỗ trợ phiên bản {supportedVersions} nhưng bạn có phiên bản {responseVersion}.", "wallet.hw.ledger.app.not.running": "Ứng dụng Cardano không chạy trên Sổ cái của bạn", + "wallet.hw.ledger.catalyst.cip36.unsupported": "Đăng ký Catalyst yêu cầu ứng dụng Ledger phiên bản 6.", "wallet.hw.ledger.catalyst.unsupported.106": "Vui lòng nâng cấp phiên bản chương trình cơ sở Ledger của bạn lên ít nhất 2.0.0 và phiên bản ứng dụng Caradano lên 2.3.2 trở lên.", "wallet.hw.ledger.common.error.101": "Thao tác bị hủy trên thiết bị Ledger.", "wallet.hw.ledger.common.error.102": "Hoạt động bị hủy bỏ bởi người dùng.", @@ -904,6 +908,7 @@ "wallet.staking.pool.unknownLabel": "Nhóm không xác định", "wallet.staking.rewards.openRewardHistory": "Mở lịch sử phần thưởng", "wallet.staking.rewards.rewardHistory": "Lịch sử phần thưởng", + "wallet.staking.rewards.rewardHistory.epochNum": "Epoch {number}", "wallet.staking.summary": "Tóm tắt", "wallet.staking.warning.pendingTx": "Bạn không thể thay đổi tùy chọn ủy quyền của mình trong khi giao dịch đang chờ xử lý", "wallet.summary.no.transaction": "Không có lịch sử giao dịch.", @@ -969,9 +974,9 @@ "wallet.transaction.state.failed": "lỗi", "wallet.transaction.state.pending": "đang giải quyết", "wallet.transaction.state.submitted": "đã gửi", - "wallet.transaction.success.button.label": "Loại giao dịch", - "wallet.transaction.success.explanation": "Kiểm tra trạng thái giao dịch từ trang giao dịch", - "wallet.transaction.success.title": "Đã gửi thành công", + "wallet.transaction.success.button.label": "Go To Transactions", + "wallet.transaction.success.explanation": "Check this transaction in the list of wallet transactions", + "wallet.transaction.success.title": "Transaction submitted", "wallet.transaction.transactionAmount": "Số tiền giao dịch", "wallet.transaction.transactionId": "ID giao dịch", "wallet.transaction.transactionMetadata": "Siêu dữ liệu giao dịch", @@ -1007,25 +1012,25 @@ "wallet.voting.dialog.completeLabel": "Hoàn thành", "wallet.voting.dialog.confirmPin": "Xác minh mã PIN", "wallet.voting.dialog.registerLabel": "Đăng ký", - "wallet.voting.dialog.step.confirm.line1": "Vui lòng nhập mã PIN vì bạn sẽ cần nó mỗi khi bạn muốn truy cập ứng dụng Catalyst Voting.", - "wallet.voting.dialog.step.pin.actionButton": "Xác nhận rằng tôi đã viết mã PIN", - "wallet.voting.dialog.step.pin.line1": "Vui lòng ghi lại mã PIN này vì bạn sẽ cần nó mỗi lần bạn muốn truy cập ứng dụng Catalyst Voting.", - "wallet.voting.dialog.step.qr.actionButton": "Xác nhận rằng tôi đã lưu mã QR", - "wallet.voting.dialog.step.qr.downloadQrCode": "Tải xuống mã QR", - "wallet.voting.dialog.step.qr.line2": "Mã QR sau đây là chứng chỉ được tạo bởi Ứng dụng Catalyst để có thể tham gia vào quá trình bỏ phiếu của Cardano.", - "wallet.voting.dialog.step.qr.line3": "Ngoài ra, chúng tôi khuyên bạn nên chụp ảnh màn hình của nó để sao lưu — bạn sẽ không thể truy cập mã QR này sau khi nhấp vào Hoàn thành.", - "wallet.voting.dialog.step.qr.lineTitle": "Sử dụng Ứng dụng bỏ phiếu Catalyst để quét mã QR", - "wallet.voting.dialog.step.register.line1": "Nhập mật khẩu chi tiêu của bạn để có thể tạo chứng chỉ cần thiết cho việc bỏ phiếu.", + "wallet.voting.dialog.step.confirm.line1": "Please enter the PIN as you will need it every time you want to access the Catalyst Voting app.", + "wallet.voting.dialog.step.pin.actionButton": "Confirm that I wrote down the PIN", + "wallet.voting.dialog.step.pin.line1": "Please write down this PIN as you will need it every time you want to access the Catalyst Voting app.", + "wallet.voting.dialog.step.qr.actionButton": "Confirm that I saved the QR code", + "wallet.voting.dialog.step.qr.downloadQrCode": "Download QR code", + "wallet.voting.dialog.step.qr.line2": "The following QR code is the generated certificate required by the Catalyst App to be able to participate in the voting process of Cardano.", + "wallet.voting.dialog.step.qr.line3": "Also we suggest to take a screenshot of it as a backup — you won’t be able to access this QR code after clicking Complete.", + "wallet.voting.dialog.step.qr.lineTitle": "Use the Catalyst Voting App to scan the QR code", + "wallet.voting.dialog.step.register.line1": "Enter your spending password to be able to generate the required certificate for voting.", "wallet.voting.dialog.step.trx.ledger.info.line.1": "Sau khi kết nối thiết bị Ledger của bạn với cổng USB của máy tính, hãy nhấn nút Đăng ký.", "wallet.voting.dialog.step.trx.line1": "Xác nhận mật khẩu chi tiêu của bạn để đăng ký trong chuỗi khối chứng chỉ được tạo trước đó để bỏ phiếu.", "wallet.voting.dialog.step.trx.trezor.info.line.1": "Sau khi kết nối thiết bị Trezor với máy tính, hãy nhấn nút Đăng ký.", - "wallet.voting.dialog.stepConfirm": "Xác nhận", + "wallet.voting.dialog.stepConfirm": "Confirm", "wallet.voting.dialog.stepPin": "PIN", - "wallet.voting.dialog.stepQrCode": "Mã QR", + "wallet.voting.dialog.stepQrCode": "QR Code", "wallet.voting.dialog.title": "Đăng ký bỏ phiếu", "wallet.voting.dialog.transactionLabel": "Giao dịch", "wallet.voting.keepDelegated": "Quyền biểu quyết của bạn là số tiền bạn ủy quyền và phần thưởng biểu quyết sẽ được phân phối tới địa chỉ phần thưởng ủy quyền của bạn. Vui lòng tiếp tục được ủy quyền cho đến khi cuộc biểu quyết kết thúc.", - "wallet.voting.ledgerNanoRequirement": "Cập nhậtứng dụng Cardano trên ví Ledger lên phiên bản 2.3.2 hoặc cao hơn Ledger Live.", + "wallet.voting.ledgerNanoRequirement": "Cập nhậtứng dụng Cardano trên ví Ledger lên phiên bản 6 hoặc cao hơn Ledger Live.", "wallet.voting.line2": "Trước khi bạn bắt đầu, hãy đảm bảo hoàn thành các bước bên dưới", "wallet.voting.line3": "Tải xuống ứng dụng bỏ phiếu Catalyst.", "wallet.voting.line4": "Mở Ứng dụng bỏ phiếu của Catalyst và nhấp vào nút Hoàn thành đăng ký.", @@ -1056,4 +1061,4 @@ "yoroiTransfer.waiting.progressInfo.checkingAddresses": "Kiểm tra địa chỉ quỹ", "yoroiTransfer.waiting.progressInfo.restoringAddresses": "Đang tìm nạp địa chỉ", "yoroiTransfer.waiting.title.label": "Ví đang được khôi phục" -} \ No newline at end of file +} diff --git a/packages/yoroi-extension/app/i18n/translations.js b/packages/yoroi-extension/app/i18n/translations.js index 44622b605f..7fe3be2d5c 100644 --- a/packages/yoroi-extension/app/i18n/translations.js +++ b/packages/yoroi-extension/app/i18n/translations.js @@ -1,4 +1,20 @@ // @flow +import en from 'react-intl/locale-data/en'; +import ko from 'react-intl/locale-data/ko'; +import ja from 'react-intl/locale-data/ja'; +import zh from 'react-intl/locale-data/zh'; +import ru from 'react-intl/locale-data/ru'; +import de from 'react-intl/locale-data/de'; +import fr from 'react-intl/locale-data/fr'; +import nl from 'react-intl/locale-data/nl'; +import pt from 'react-intl/locale-data/pt'; +import id from 'react-intl/locale-data/id'; +import es from 'react-intl/locale-data/es'; +import it from 'react-intl/locale-data/it'; +import tr from 'react-intl/locale-data/tr'; +import cs from 'react-intl/locale-data/cs'; +import sk from 'react-intl/locale-data/sk'; +import vi from 'react-intl/locale-data/vi'; import globalMessages from './global-messages'; import type { $npm$ReactIntl$MessageDescriptor } from 'react-intl'; import { ReactComponent as EnglishFlag } from '../assets/images/flags/english.inline.svg'; @@ -16,9 +32,28 @@ import { ReactComponent as IndonesianFlag } from '../assets/images/flags/indone import { ReactComponent as TurkishFlag } from '../assets/images/flags/turkish.inline.svg'; import { ReactComponent as CzechFlag } from '../assets/images/flags/czech.inline.svg'; import { ReactComponent as SlovakFlag } from '../assets/images/flags/slovak.inline.svg'; +import { ReactComponent as VietnameseFlag } from '../assets/images/flags/vietnamese.inline.svg'; -// This is essentially bulk require +export const locales: any = Object.freeze([ + ...en, + ...ko, + ...ja, + ...zh, + ...ru, + ...de, + ...fr, + ...nl, + ...pt, + ...id, + ...es, + ...it, + ...tr, + ...cs, + ...sk, + ...vi, +]); +// This is essentially bulk require // $FlowExpectedError[prop-missing] require.context comes from webpack const req = require.context('./locales', true, /\.json.*$/, 'lazy'); export const translations: {| @@ -116,5 +151,10 @@ export const LANGUAGES: Array = [ value: 'sk-SK', label: globalMessages.languageSlovak, svg: SlovakFlag + }, + { + value: 'vi-VN', + label: globalMessages.languageVietnamese, + svg: VietnameseFlag } ]; diff --git a/packages/yoroi-extension/app/stores/toplevel/WalletSettingsStore.js b/packages/yoroi-extension/app/stores/toplevel/WalletSettingsStore.js index b6e4fdc01b..aa0b467c4e 100644 --- a/packages/yoroi-extension/app/stores/toplevel/WalletSettingsStore.js +++ b/packages/yoroi-extension/app/stores/toplevel/WalletSettingsStore.js @@ -276,7 +276,7 @@ export default class WalletSettingsStore extends Store { } await removeWalletFromLS(request.publicDeriver) - // remove this wallet from wallet sort list + // Remove this wallet from wallet sort list const walletType = getWalletType(request.publicDeriver) const walletsNavigation = this.stores.profile.walletsNavigation const newWalletsNavigation = { @@ -285,9 +285,22 @@ export default class WalletSettingsStore extends Store { [walletType]: walletsNavigation[walletType].filter( walletId => walletId !== request.publicDeriver.publicDeriverId) } - await this.actions.profile.updateSortedWalletList.trigger(newWalletsNavigation); + // ==================== Disconnect related dApps ==================== + await this.actions.connector.getConnectorWhitelist.trigger(); + const connectorWhitelist = this.stores.connector.currentConnectorWhitelist; + const connectedDapps = connectorWhitelist.filter( + dapp => dapp.publicDeriverId === request.publicDeriver.publicDeriverId + ); + + for (const dapp of connectedDapps) { + await this.actions.connector.removeWalletFromWhitelist.trigger({ + protocol: dapp.protocol, + url: dapp.url, + }); + } + await this.removeWalletRequest.execute({ publicDeriver: request.publicDeriver, conceptualWallet: group.publicDerivers.length === 1 diff --git a/packages/yoroi-extension/features/01-connector-cardano.feature b/packages/yoroi-extension/features/01-connector-cardano.feature index 7b9cb9e7d3..d50f7f1ef2 100644 --- a/packages/yoroi-extension/features/01-connector-cardano.feature +++ b/packages/yoroi-extension/features/01-connector-cardano.feature @@ -32,9 +32,10 @@ Feature: dApp connector data signing | amount | toAddress | | 3 | addr1q97xu8uvdgjpqum6sjv9vptzulkc53x7tk69vj2lynywxppq3e92djqml4tjxz2avcgem3u8z7r54yvysm20qasxx5gqyx8evw | Then I should see the connector popup for signing + # remove minus sign after the fix https://emurgo.atlassian.net/browse/YOEXT-577 And I should see the transaction amount data: | amount | fee | - | 3 | 0.168317 | + | -3 | 0.168317 | And I should see the transaction addresses info: | fromAddress | fromAddressAmount | toAddress | toAddressAmount | | addr1...ajfkn | -5.5 | addr1...x8evw | 3 | @@ -56,9 +57,10 @@ Feature: dApp connector data signing | amount | toAddress | | 3 | addr1q97xu8uvdgjpqum6sjv9vptzulkc53x7tk69vj2lynywxppq3e92djqml4tjxz2avcgem3u8z7r54yvysm20qasxx5gqyx8evw | Then I should see the connector popup for signing + # remove minus sign after the fix https://emurgo.atlassian.net/browse/YOEXT-577 And I should see the transaction amount data: | amount | fee | - | 3 | 0.168317 | + | -3 | 0.168317 | And I should see the transaction addresses info: | fromAddress | fromAddressAmount | toAddress | toAddressAmount | | addr1...ajfkn | -5.5 | addr1...x8evw | 3 | diff --git a/packages/yoroi-extension/features/02-connector-anonymous-wallet-errors-checking.feature b/packages/yoroi-extension/features/02-connector-anonymous-wallet-errors-checking.feature index e0da07c331..760e59d433 100644 --- a/packages/yoroi-extension/features/02-connector-anonymous-wallet-errors-checking.feature +++ b/packages/yoroi-extension/features/02-connector-anonymous-wallet-errors-checking.feature @@ -23,6 +23,8 @@ Feature: dApp connector anonymous wallet errors checking And I select the only wallet named shelley-simple-15 with 5.5 balance Then The popup window should be closed And The access request should succeed + And The wallet shelley-simple-15 is connected to the website localhost + And The dApp should see balance 5500000 Then I request signing the transaction: | amount | toAddress | | 3 | addr1q97xu8uvdgjpqum6sjv9vptzulkc53x7tk69vj2lynywxppq3e92djqml4tjxz2avcgem3u8z7r54yvysm20qasxx5gqyx8evw | @@ -47,6 +49,8 @@ Feature: dApp connector anonymous wallet errors checking And I select the only wallet named shelley-simple-15 with 5.5 balance Then The popup window should be closed And The access request should succeed + And The wallet shelley-simple-15 is connected to the website localhost + And The dApp should see balance 5500000 Then I request signing the transaction: | amount | toAddress | | 3 | addr1q97xu8uvdgjpqum6sjv9vptzulkc53x7tk69vj2lynywxppq3e92djqml4tjxz2avcgem3u8z7r54yvysm20qasxx5gqyx8evw | @@ -62,6 +66,7 @@ Feature: dApp connector anonymous wallet errors checking Then The popup window should be closed And The access request should succeed And The wallet shelley-simple-15 is connected to the website localhost + And The dApp should see balance 5500000 Then I request unused addresses And I request signing the data: | payload | diff --git a/packages/yoroi-extension/features/03-connector-authorized-wallet-errors-checking.feature b/packages/yoroi-extension/features/03-connector-authorized-wallet-errors-checking.feature index e2150f28e9..ba1d14e554 100644 --- a/packages/yoroi-extension/features/03-connector-authorized-wallet-errors-checking.feature +++ b/packages/yoroi-extension/features/03-connector-authorized-wallet-errors-checking.feature @@ -40,6 +40,8 @@ Feature: dApp connector errors checking Then I enter the spending password asdfasdfasdf and click confirm Then The popup window should be closed And The access request should succeed + And The wallet shelley-simple-15 is connected to the website localhost + And The dApp should see balance 5500000 Then I request signing the transaction: | amount | toAddress | | 3 | addr1q97xu8uvdgjpqum6sjv9vptzulkc53x7tk69vj2lynywxppq3e92djqml4tjxz2avcgem3u8z7r54yvysm20qasxx5gqyx8evw | @@ -66,6 +68,8 @@ Feature: dApp connector errors checking Then I enter the spending password asdfasdfasdf and click confirm Then The popup window should be closed And The access request should succeed + And The wallet shelley-simple-15 is connected to the website localhost + And The dApp should see balance 5500000 Then I request signing the transaction: | amount | toAddress | | 3 | addr1q97xu8uvdgjpqum6sjv9vptzulkc53x7tk69vj2lynywxppq3e92djqml4tjxz2avcgem3u8z7r54yvysm20qasxx5gqyx8evw | diff --git a/packages/yoroi-extension/features/mock-chain/TestWallets.js b/packages/yoroi-extension/features/mock-chain/TestWallets.js index 87aef41daf..8abbc5f345 100644 --- a/packages/yoroi-extension/features/mock-chain/TestWallets.js +++ b/packages/yoroi-extension/features/mock-chain/TestWallets.js @@ -7,8 +7,8 @@ export type RestorationInput = {| password: string, mnemonic: string, plate: string, - plateByron?: string, - deviceId?: ?string, + plateByron: string, + deviceId: string, |}; function getMnemonicFromEnv(walletName): string { @@ -19,16 +19,17 @@ function createWallet(payload: {| name: string, mnemonic: string, plate: string, - plateByron?: ?string, - deviceId?: ?string, + plateByron: string, + deviceId: string, |}) { - const { name, mnemonic, plate } = payload; + const { name, mnemonic, plate, plateByron, deviceId } = payload; return { [name]: { name, mnemonic, plate, + plateByron, password: commonWalletPassword, - deviceId: payload.deviceId, + deviceId, } }; } @@ -67,33 +68,44 @@ export const testWallets: { [key: WalletNames]: RestorationInput, ... } = Object createWallet({ name: ('small-single-tx': WalletNames), mnemonic: 'eight country switch draw meat scout mystery blade tip drift useless good keep usage title', - plate: 'EAJD-7036', + plate: '', + plateByron: 'EAJD-7036', + deviceId: '', }), createWallet({ name: ('failed-single-tx': WalletNames), mnemonic: 'broken common spring toilet work safe decrease equal velvet cluster myth old toy hold rain', plate: 'JSLX-5059', + plateByron: '', + deviceId: '', }), createWallet({ name: ('many-tx-wallet': WalletNames), mnemonic: 'final autumn bacon fold horse scissors act pole country focus task blush basket move view', plate: 'ZKTZ-4614', + plateByron: '', + deviceId: '', }), createWallet({ name: ('empty-wallet': WalletNames), mnemonic: 'burst hood dance captain city crane over olive notice sugar what bubble butter wealth grace', plate: 'PZEB-5741', plateByron: 'ZPOX-6942', + deviceId: '', }), createWallet({ name: ('simple-pending-wallet': WalletNames), mnemonic: 'ritual horn upon plastic foster enemy expect hand control coil jeans wolf arch isolate farm', plate: 'DPAH-1099', + plateByron: '', + deviceId: '', }), createWallet({ name: ('tx-big-input-wallet': WalletNames), mnemonic: 'dragon mango general very inmate idea rabbit pencil element bleak term cart critic kite pill', plate: 'EDAO-9229', + plateByron: '', + deviceId: '', }), createWallet({ // a wallet to send stuff to when you need a tx output @@ -101,11 +113,15 @@ export const testWallets: { [key: WalletNames]: RestorationInput, ... } = Object name: ('dump-wallet': WalletNames), mnemonic: 'proud nuclear patch arm digital theory peasant winner person knock mirror across immune certain power', plate: 'XXXX-1111', + plateByron: '', + deviceId: '', }), createWallet({ name: ('jormungandr-test': WalletNames), mnemonic: '', plate: 'XXXX-1111', + plateByron: '', + deviceId: '', }), createWallet({ name: ('ledger-wallet': WalletNames), @@ -125,72 +141,98 @@ export const testWallets: { [key: WalletNames]: RestorationInput, ... } = Object name: ('shelley-simple-24': WalletNames), mnemonic: 'reunion walnut update express purse defense slice barrel estate olympic february flock give team alert coast luggage exhaust notable bag december split furnace sponsor', plate: 'DSKC-9213', + plateByron: '', + deviceId: '', }), createWallet({ name: ('shelley-collateral': WalletNames), mnemonic: 'deal calm cloth world refuse pledge grant tuna inner body fat afford absorb off barely', plate: 'HLBZ-9462', + plateByron: '', + deviceId: '', }), createWallet({ name: ('shelley-simple-15': WalletNames), mnemonic: 'eight country switch draw meat scout mystery blade tip drift useless good keep usage title', plate: 'ZDDC-9858', + plateByron: '', + deviceId: '', }), createWallet({ name: ('shelley-delegated': WalletNames), mnemonic: 'parrot offer switch thank film high drop salute task train squirrel coral consider coyote evolve', plate: 'PALP-0076', + plateByron: '', deviceId: '6495958994A4025BB5EE1DB1', }), createWallet({ name: ('shelley-ledger-delegated': WalletNames), mnemonic: 'parrot offer switch thank film high drop salute task train squirrel coral consider coyote evolve', plate: 'PALP-0076', + plateByron: '', deviceId: '707fa118bf6b84', }), createWallet({ name: ('shelley-only-registered': WalletNames), mnemonic: 'pig organ result afraid abstract arrest brass kangaroo hub cube crunch return vibrant core make', plate: 'TDDO-4310', + plateByron: '', + deviceId: '', }), createWallet({ name: ('shelley-enterprise': WalletNames), mnemonic: 'much million increase spot visa domain grow brother chief mechanic innocent envelope vacant bundle coyote', plate: 'HBDZ-9545', + plateByron: '', + deviceId: '', }), createWallet({ name: ('shelley-mangled': WalletNames), mnemonic: 'weekend december choose maid rack helmet canoe bridge strike section lift autumn route practice seat', plate: 'JCEH-5025', + plateByron: '', + deviceId: '', }), createWallet({ name: ('ergo-simple-wallet': WalletNames), mnemonic: 'eight country switch draw meat scout mystery blade tip drift useless good keep usage title', plate: 'CXTP-1821', + plateByron: '', + deviceId: '', }), createWallet({ name: ('ergo-token-wallet': WalletNames), mnemonic: 'rent sword help dynamic enhance collect biology drama agent raven grape bike march length leisure', plate: 'AZTH-1588', + plateByron: '', + deviceId: '', }), createWallet({ name: ('cardano-token-wallet': WalletNames), mnemonic: 'rent sword help dynamic enhance collect biology drama agent raven grape bike march length leisure', plate: 'HZPX-1482', + plateByron: '', + deviceId: '', }), createWallet({ name: ('First-Smoke-Test-Wallet': WalletNames), mnemonic: getMnemonicFromEnv('FIRST_SMOKE_TEST_WALLET'), - plate: 'XONT-4910' + plate: 'XONT-4910', + plateByron: '', + deviceId: '', }), createWallet({ name: ('Second-Smoke-Test-Wallet': WalletNames), mnemonic: getMnemonicFromEnv('SECOND_SMOKE_TEST_WALLET'), plate: 'XZHD-1651', + plateByron: '', + deviceId: '', }), createWallet({ name: ('Second-Smoke-Test-Wallet-FF': WalletNames), mnemonic: getMnemonicFromEnv('SECOND_SMOKE_TEST_WALLET_FF'), - plate: 'CJBE-8896' + plate: 'CJBE-8896', + plateByron: '', + deviceId: '', }), ); diff --git a/packages/yoroi-extension/features/mock-dApp-webpage/index.js b/packages/yoroi-extension/features/mock-dApp-webpage/index.js index 6d6f5fb9ce..97939b8757 100644 --- a/packages/yoroi-extension/features/mock-dApp-webpage/index.js +++ b/packages/yoroi-extension/features/mock-dApp-webpage/index.js @@ -229,11 +229,11 @@ export class MockDAppWebpage { callback({ success: true, error: null, retValue: null }); }, error => { - callback({ success: false, error: error.message, retValue: null }); + callback({ success: false, error, retValue: null }); } ) .catch(error => { - callback({ success: false, error: error.message, retValue: null }); + callback({ success: false, error, retValue: null }); }); }): DAppConnectorResponse); this.logger.info(`MockDApp: -> The access response: ${JSON.stringify(accessResponse)}`); diff --git a/packages/yoroi-extension/features/pages/connector-connectWalletPage.js b/packages/yoroi-extension/features/pages/connector-connectWalletPage.js index 6247e226d6..8cefb0e8e3 100644 --- a/packages/yoroi-extension/features/pages/connector-connectWalletPage.js +++ b/packages/yoroi-extension/features/pages/connector-connectWalletPage.js @@ -14,31 +14,39 @@ export const createWalletBtn: LocatorObject = { method: 'css', }; export const walletListElement: LocatorObject = { locator: '.ConnectPage_list', method: 'css' }; -export const walletNameField: LocatorObject = { locator: 'div.WalletCard_name', method: 'css' }; +export const walletNameField: LocatorObject = { + locator: 'div.ConnectedWallet_nameWrapper', + method: 'css', +}; export const walletItemButton: LocatorObject = { locator: './button', method: 'xpath' }; -export const walletBalanceField: LocatorObject = { locator: '.WalletCard_balance', method: 'css' }; +export const walletBalanceField: LocatorObject = { locator: '.AmountDisplay_amount', method: 'css' }; export const spendingPasswordInput: LocatorObject = { - locator: '//input[@name="walletPassword"]', - method: 'xpath', + locator: 'walletPassword', + method: 'id', }; export const spendingPasswordErrorField: LocatorObject = { - locator: '//p[starts-with(@id, "walletPassword--") and contains(@id, "-helper-text")]', - method: 'xpath', + locator: 'walletPassword-helper-text', + method: 'id', }; export const eyeButton: LocatorObject = { locator: '.MuiIconButton-edgeEnd', method: 'css' }; -export const confirmButton: LocatorObject = { locator: '.MuiButton-primary', method: 'css' }; -export const backButton: LocatorObject = { locator: '.MuiButton-secondary', method: 'css' }; +export const confirmButton: LocatorObject = { locator: 'confirmButton', method: 'id' }; +export const backButton: LocatorObject = { locator: 'backButton', method: 'id' }; export const getWallets = async (customWorld: Object): Promise> => { const walletList = await customWorld.waitForElement(walletListElement); return await walletList.findElements(By.css('li')); }; -export const getWalletName = async (wallets: Array, index: number): Promise => { +export const getWalletNameAndPlate = async ( + wallets: Array, + index: number +): Promise<{| walletName: string, walletPlate: string |}> => { const walletNameFieldElem = await wallets[index].findElement( getMethod(walletNameField.method)(walletNameField.locator) ); - return await walletNameFieldElem.getText(); + const fullText = await walletNameFieldElem.getText(); + const [name, walletPlate] = fullText.split('\n') + return { walletName: name, walletPlate }; }; export const getWalletBalance = async ( diff --git a/packages/yoroi-extension/features/pages/connector-getCollateralPage.js b/packages/yoroi-extension/features/pages/connector-getCollateralPage.js index 5ecc55ae16..e452fdb1b5 100644 --- a/packages/yoroi-extension/features/pages/connector-getCollateralPage.js +++ b/packages/yoroi-extension/features/pages/connector-getCollateralPage.js @@ -3,16 +3,26 @@ import type { LocatorObject } from '../support/webdriver'; export const addCollateralTitle: LocatorObject = { - locator: '//h5[contains(text(), "Add Collateral")]', - method: 'xpath', + locator: 'addCollateralTitle', + method: 'id', }; export const transactionFeeTitle: LocatorObject = { - locator: '//p[contains(text(), "Transaction Fee")]', - method: 'xpath', + locator: 'addCollateralFeeTitle', + method: 'id', }; export const totalAmountTitle: LocatorObject = { - locator: '//p[contains(text(), "Total Amount")]', - method: 'xpath', + locator: 'addCollateralAmountTitle', + method: 'id', +}; + +export const getCollateralTransactionFee = async (customWorld: Object): Promise => { + const feeFieldElement = await customWorld.findElement(transactionFeeTitle); + return (await feeFieldElement.getText()).split(' ')[0]; +}; + +export const getCollateralTransactionAmount = async (customWorld: Object): Promise => { + const allAmountBlocks = await customWorld.findElement(totalAmountTitle); + return (await allAmountBlocks.getText()).split(' ')[0]; }; diff --git a/packages/yoroi-extension/features/pages/connector-signingDataPage.js b/packages/yoroi-extension/features/pages/connector-signingDataPage.js index b84d0d44b5..14fee94f30 100644 --- a/packages/yoroi-extension/features/pages/connector-signingDataPage.js +++ b/packages/yoroi-extension/features/pages/connector-signingDataPage.js @@ -3,13 +3,13 @@ import type { LocatorObject } from '../support/webdriver'; export const signMessageTitle: LocatorObject = { - locator: '//h5[contains(text(), "Sign Message")]', - method: 'xpath', + locator: 'signMessageTitle', + method: 'id', }; export const dataText: LocatorObject = { - locator: '//pre', - method: 'xpath', + locator: 'signMessageBox-payload', + method: 'id', }; export const getSigningData = async (customWorld: Object): Promise => { diff --git a/packages/yoroi-extension/features/pages/connector-signingTxPage.js b/packages/yoroi-extension/features/pages/connector-signingTxPage.js index f5c293eeb7..fbcb3e06bb 100644 --- a/packages/yoroi-extension/features/pages/connector-signingTxPage.js +++ b/packages/yoroi-extension/features/pages/connector-signingTxPage.js @@ -2,6 +2,7 @@ import { By, WebElement } from 'selenium-webdriver'; import type { LocatorObject } from '../support/webdriver'; +import { getMethod } from '../support/helpers/helpers'; type AddressWithAmount = {| address: string, @@ -13,57 +14,94 @@ type AddressesWithAmount = {| toAddresses: Array, |}; -const overview = 'Overview'; -const utxoAddresses = 'UTXO addresses'; -const getTabButton = (tabName: string) => - `//div[@role="tablist"]/button[contains(text(), "${tabName}")]`; +const detailsTabName = 'Details'; +const utxosTabName = 'UTxOs'; +const connectionTabName = 'Connection'; -export const transactionFeeTitle: LocatorObject = { - locator: '//p[contains(text(), "Transaction Fee")]', - method: 'xpath', +const getTabButton = (tabName: string) => `//div[@role="tablist"]/button/p[text()="${tabName}"]`; + +export const transactionFeeText: LocatorObject = { + locator: 'signTxAdditionalInfoPanelBox-fee', + method: 'id', +}; + +export const summaryBox: LocatorObject = { + locator: 'signTxMessagesSummaryBox', + method: 'id', }; export const transactionTotalAmountField: LocatorObject = { - locator: '//p[contains(text(), "Total Amount")]', - method: 'xpath', + locator: 'signTxMessagesSummaryBox-total', + method: 'id', }; -const addressesPanel: LocatorObject = { - locator: '//div[@role="tabpanel"][2]/div/div/div', - method: 'xpath', +const amountTextField: LocatorObject = { + locator: 'asseetValueDisplayBox', + method: 'id', +}; + +const fromAddressYourInputs: LocatorObject = { + locator: 'fromAddressesBox-yourInputs', + method: 'id', }; -const getToAddressesPanel = async (customWorld: Object): Promise => { - return (await customWorld.findElements(addressesPanel))[1]; +const fromAddressForeignInputs: LocatorObject = { + locator: 'fromAddressesBox-foreignInputs', + method: 'id', }; -const getFromAddressesPanel = async (customWorld: Object): Promise => { - return (await customWorld.findElements(addressesPanel))[0]; +const toAddressYourInputs: LocatorObject = { + locator: 'toAddressesBox-yourOutputs', + method: 'id', +}; + +const toAddressForeignInputs: LocatorObject = { + locator: 'toAddressesBox-foreignOutputs', + method: 'id', +}; + +const addressRowLocator: LocatorObject = { + locator: 'addressRow', + method: 'id', +}; + +const addressRowAddressInfo: LocatorObject = { + locator: './div[@class="CopyableAddress_component"]', + method: 'xpath', +} + +const addressRowAmount: LocatorObject = { + locator: 'addressRow-amount', + method: 'id', }; const getAddressesRows = async (addressPart: WebElement): Promise> => { - return await addressPart.findElements(By.xpath('./div[2]/div')); + return await addressPart.findElements( + getMethod(addressRowLocator.method)(addressRowLocator.locator) + ); }; const getAddressFromRow = async (addressRow: WebElement): Promise => { const addressElement = await addressRow.findElement( - By.xpath('./div[@class="CopyableAddress_component"]') + getMethod(addressRowAddressInfo.method)(addressRowAddressInfo.locator) ); return await addressElement.getText(); }; // should be improved in case of several outputs const getAmountFromRow = async (addressRow: WebElement): Promise => { - const amountElement = await addressRow.findElement(By.xpath('./div[2]')); + const amountElement = await addressRow.findElement( + getMethod(addressRowAmount.method)(addressRowAmount.locator) + ); return (await amountElement.getText()).split(' ')[0]; }; const getAddresses = async (addressesPart: WebElement): Promise> => { const result = []; - const fromAddressesRows = await getAddressesRows(addressesPart); - for (const fromAddressesRow of fromAddressesRows) { - const address = await getAddressFromRow(fromAddressesRow); - const amountString = await getAmountFromRow(fromAddressesRow); + const addressesRows = await getAddressesRows(addressesPart); + for (const addressesRow of addressesRows) { + const address = await getAddressFromRow(addressesRow); + const amountString = await getAmountFromRow(addressesRow); const amount = parseFloat(amountString); result.push({ address, @@ -74,34 +112,68 @@ const getAddresses = async (addressesPart: WebElement): Promise> => { - const fromAddressesPart = await getFromAddressesPanel(customWorld); - return await getAddresses(fromAddressesPart); + const result = []; + if (await customWorld.checkIfExists(fromAddressYourInputs)) { + const fromAddressesYourInputsBoxElem = await customWorld.findElement(fromAddressYourInputs); + const fromAddressesYourArr = await getAddresses(fromAddressesYourInputsBoxElem); + result.push(...fromAddressesYourArr); + } + if (await customWorld.checkIfExists(fromAddressForeignInputs)) { + const fromAddressesForeignInputsBoxElem = await customWorld.findElement( + fromAddressForeignInputs + ); + const fromAddressesForeignArr = await getAddresses(fromAddressesForeignInputsBoxElem); + result.push(...fromAddressesForeignArr); + } + + return result; }; -const getToAddresses = async (customWorld: Object): Promise> => { - const toAddressesPart = await getToAddressesPanel(customWorld); - return await getAddresses(toAddressesPart); +const getToAddresses = async (customWorld): Promise> => { + const result = []; + if (await customWorld.checkIfExists(toAddressYourInputs)) { + const toAddressesYourInputsBoxElem = await customWorld.findElement(toAddressYourInputs); + const toAddressesYourArr = await getAddresses(toAddressesYourInputsBoxElem); + result.push(...toAddressesYourArr); + } + if (await customWorld.checkIfExists(toAddressForeignInputs)) { + const toAddressesForeignInputsBoxElem = await customWorld.findElement( + toAddressForeignInputs + ); + const toAddressesForeignArr = await getAddresses(toAddressesForeignInputsBoxElem); + result.push(...toAddressesForeignArr); + } + + return result; +}; + +export const detailsTabButton: LocatorObject = { + locator: getTabButton(detailsTabName), + method: 'xpath', }; -export const overviewTabButton: LocatorObject = { - locator: getTabButton(overview), +export const utxosTabButton: LocatorObject = { + locator: getTabButton(utxosTabName), method: 'xpath', }; -export const utxoAddressesTabButton: LocatorObject = { - locator: getTabButton(utxoAddresses), +export const connectionTabButton: LocatorObject = { + locator: getTabButton(connectionTabName), method: 'xpath', }; export const walletBalanceField: LocatorObject = { locator: '.WalletCard_balance', method: 'css' }; export const getTransactionFee = async (customWorld: Object): Promise => { - const titleElement = await customWorld.findElement(transactionFeeTitle); - const parentElement = await titleElement.findElement(By.xpath('./..')); - const amountFieldElement = (await parentElement.findElements(By.xpath('./p')))[1]; + const amountFieldElement = await customWorld.findElement(transactionFeeText); return (await amountFieldElement.getText()).split(' ')[0]; }; +export const getTransactionSentAmount = async (customWorld: Object): Promise => { + const allAmountBlocks = await customWorld.findElements(amountTextField); + return (await allAmountBlocks[0].getText()).split(' ')[0]; +}; + export const getTransactionAmount = async (customWorld: Object): Promise => { const titleElement = await customWorld.findElement(transactionTotalAmountField); const parentElement = await titleElement.findElement(By.xpath('./..')); @@ -109,8 +181,8 @@ export const getTransactionAmount = async (customWorld: Object): Promise return (await amountFieldElement.getText()).split(' ')[0]; }; -export const confirmButton: LocatorObject = { locator: '.MuiButton-primary', method: 'css' }; -export const cancelButton: LocatorObject = { locator: '.MuiButton-secondary', method: 'css' }; +export const confirmButton: LocatorObject = { locator: 'confirmButton', method: 'id' }; +export const cancelButton: LocatorObject = { locator: 'cancelButton', method: 'id' }; export const getUTXOAddresses = async (customWorld: Object): Promise => { const fromAddresses = await getFromAddresses(customWorld); diff --git a/packages/yoroi-extension/features/pages/newWalletPages.js b/packages/yoroi-extension/features/pages/newWalletPages.js index e18b42ed76..88c65b1d1a 100644 --- a/packages/yoroi-extension/features/pages/newWalletPages.js +++ b/packages/yoroi-extension/features/pages/newWalletPages.js @@ -17,10 +17,6 @@ export const pickUpCurrencyDialog: LocatorObject = { locator: '.PickCurrencyOptionDialog', method: 'css', }; -export const pickUpCurrencyDialogErgo: LocatorObject = { - locator: '.PickCurrencyOptionDialog_ergo', - method: 'css', -}; export const pickUpCurrencyDialogCardano: LocatorObject = { locator: '.PickCurrencyOptionDialog_cardano', method: 'css', @@ -75,18 +71,6 @@ export const trezorWalletName: LocatorObject = { }; export const trezorConfirmButton: LocatorObject = { locator: '.MuiButton-primary', method: 'css' }; // Create wallet dialog -export const createOptionDialog: LocatorObject = { - locator: '.WalletCreateOptionDialog', - method: 'css', -}; -export const createNormalWalletButton: LocatorObject = { - locator: '.WalletCreateOptionDialog_createWallet', - method: 'css' -}; -export const createPaperWalletButton: LocatorObject = { - locator: '.WalletCreateOptionDialog_restorePaperWallet', - method: 'css', -}; export const createWalletPasswordInput: LocatorObject = { locator: '.WalletCreateDialog .walletPassword input', method: 'css', @@ -140,34 +124,20 @@ export const getRecoveryPhraseWord = (indexNumber: number): LocatorObject => { }; }; -// Paper Wallet dialog -export const paperWalletDialogSelect: LocatorObject = { - locator: '.WalletPaperDialog_component .MuiSelect-select', - method: 'css', -}; -export const restorePaperWalletButton: LocatorObject = { - locator: '.WalletRestoreOptionDialog_restorePaperWallet', - method: 'css', -}; export const restoreDialogButton: LocatorObject = { locator: '.WalletRestoreDialog .primary', method: 'css', }; -export const getAddressesAmountButton = (addressesAmount: string): LocatorObject => { - return { locator: `//li[contains(text(), "${addressesAmount}")]`, method: 'xpath' }; -}; + export const recoveryPhraseDeleteIcon = { locator: `(//span[contains(text(), '×')])[1]`, method: 'xpath', }; + export const recoveryPhraseError: LocatorObject = { locator: '//p[starts-with(@id, "recoveryPhrase--")]', method: 'xpath', }; -export const addressElement : LocatorObject = { - locator: '//span[contains(@class, "RawHash_hash")]', - method: 'xpath', -}; // Common elements export const walletNameInput: LocatorObject = { diff --git a/packages/yoroi-extension/features/pages/restoreWalletPage.js b/packages/yoroi-extension/features/pages/restoreWalletPage.js index 53f5e7c93c..ce33de8ad0 100644 --- a/packages/yoroi-extension/features/pages/restoreWalletPage.js +++ b/packages/yoroi-extension/features/pages/restoreWalletPage.js @@ -49,7 +49,6 @@ export const walletNameInput: LocatorObject = { locator: "input[name='walletName export const confirmRestoreWalletButton: LocatorObject = { locator: '.WalletRestoreDialog .primary', method: 'css' }; export const walletPasswordInput: LocatorObject = { locator: "input[name='walletPassword']", method: 'css' }; export const repeatPasswordInput: LocatorObject = { locator: "input[name='repeatPassword']", method: 'css' }; -export const paperPasswordInput: LocatorObject = { locator: "input[name='paperPassword']", method: 'css' }; export const confirmButton: LocatorObject = { locator: '.confirmButton', method: 'css' }; export const confirmConfirmationButton: LocatorObject = { locator: '.WalletRestoreDialog .primary', method: 'css' }; export const verifyRestoredInfoDialog: LocatorObject = { locator: '.WalletRestoreVerifyDialog_dialog', method: 'css' }; diff --git a/packages/yoroi-extension/features/pages/settingsPage.js b/packages/yoroi-extension/features/pages/settingsPage.js index 50dc4d160a..29627b69e8 100644 --- a/packages/yoroi-extension/features/pages/settingsPage.js +++ b/packages/yoroi-extension/features/pages/settingsPage.js @@ -9,10 +9,6 @@ export async function selectSubmenuSettings(customWorld: Object, buttonName: str const formattedButtonName = camelCase(buttonName); const buttonSelector = `.SubMenuItem_component.${formattedButtonName}`; await customWorld.click({ locator: buttonSelector, method: 'css' }); - await customWorld.waitForElement({ - locator: `.SubMenuItem_component.SubMenuItem_active.${formattedButtonName}`, - method: 'css', - }); } export async function goToSettings(customWorld: Object) { diff --git a/packages/yoroi-extension/features/step_definitions/common-steps.js b/packages/yoroi-extension/features/step_definitions/common-steps.js index 3607108ab7..b7551e86d5 100644 --- a/packages/yoroi-extension/features/step_definitions/common-steps.js +++ b/packages/yoroi-extension/features/step_definitions/common-steps.js @@ -50,16 +50,12 @@ import { trezorConfirmButton, walletNameInput, saveDialog, - pickUpCurrencyDialogErgo, walletRestoreOptionDialog, restoreNormalWallet, - walletRestoreDialog, restoreWalletButton, saveButton, byronEraButton, createWalletButton, - createOptionDialog, - createNormalWalletButton, } from '../pages/newWalletPages'; import { allowPubKeysAndSwitchToYoroi, switchToTrezorAndAllow } from './trezor-steps'; import { @@ -276,8 +272,9 @@ export async function getIndexedDBTablesInfo(customWorld: any, postfix: string = } }; -export async function getPlates(customWorld: any): Promise { +export async function getPlates(customWorld: any): Promise> { // check plate in confirmation dialog + await customWorld.waitForElement(restoringDialogPlate); let plateElements = await customWorld.findElements(restoringDialogPlate); // this makes this function also work for wallets that already exist @@ -437,25 +434,6 @@ Then(/^I pause the test to debug$/, async function () { await this.waitForElement({ locator: '.element_that_does_not_exist', method: 'css' }); }); -Given(/^There is an Ergo wallet stored named ([^"]*)$/, async function (walletName) { - this.webDriverLogger.info(`Step: There is an Ergo wallet stored named ${walletName}`); - const restoreInfo = testWallets[walletName]; - expect(restoreInfo).to.not.equal(undefined); - - await this.click(restoreWalletButton); - - await this.waitForElement(pickUpCurrencyDialog); - await this.click(pickUpCurrencyDialogErgo); - - await this.waitForElement(walletRestoreOptionDialog); - - await this.click(restoreNormalWallet); - await this.waitForElement(walletRestoreDialog); - - await inputMnemonicForWallet(this, restoreInfo); - await checkWalletPlate(this, walletName, restoreInfo); -}); - Given(/^There is a Shelley wallet stored named ([^"]*)$/, async function (walletName: WalletNames) { this.webDriverLogger.info(`Step: There is a Shelley wallet stored named ${walletName}`); const browserName = await this.getBrowser(); @@ -477,9 +455,6 @@ Given(/^I create a new Shelley wallet with the name ([^"]*)$/, async function (w await this.waitForElement(pickUpCurrencyDialog); await this.click(getCurrencyButton('cardano')); - await this.waitForElement(createOptionDialog); - await this.click(createNormalWalletButton); - await this.waitForElement(walletInfoDialog); await this.input(walletNameInput, walletName); await this.input(walletPasswordInput, commonWalletPassword); @@ -560,6 +535,10 @@ Given(/^I have opened the extension$/, async function () { if (browserName === 'firefox') { await this.driver.manage().window().maximize(); } + // this string is for local debug only. It sets the same resolution as on Github virtual display + if (process.env.LIKE_GITHUB_DISPLAY != null && process.env.LIKE_GITHUB_DISPLAY === '1') { + this.driver.manage().window().setRect({ x: 0, y: 0, width: 989, height: 1113 }); + } }); Given(/^I refresh the page$/, async function () { @@ -636,6 +615,7 @@ Given(/^I connected Trezor device ([^"]*)$/, async function (deviceId) { Given(/^I connected Trezor emulator device$/, async function () { // select connecting a HW wallet + this.webDriverLogger.info(`Step: I connected Trezor device`); await this.click(connectHwButton); // pick up currency await this.waitForElement(pickUpCurrencyDialog); @@ -657,6 +637,10 @@ Given(/^I connected Trezor emulator device$/, async function () { const name = await this.getValue(walletNameInput); expect(name).to.be.equal('Emulator'); await this.click(saveButton); + this.webDriverLogger.info(`Step: Wallet is connected and saved`); + await this.waitForElement(walletSyncingOverlayComponent); + await this.waitForElementNotPresent(walletSyncingOverlayComponent); + this.webDriverLogger.info(`Step: Wallet is fully synchronized`); }); async function restoreWalletsFromStorage(client) { diff --git a/packages/yoroi-extension/features/step_definitions/connector-steps.js b/packages/yoroi-extension/features/step_definitions/connector-steps.js index a97f101ca0..f6c52c3c28 100644 --- a/packages/yoroi-extension/features/step_definitions/connector-steps.js +++ b/packages/yoroi-extension/features/step_definitions/connector-steps.js @@ -7,7 +7,7 @@ import { confirmButton, createWalletBtn, getWalletBalance, - getWalletName, + getWalletNameAndPlate, getWallets, logoElement, noWalletsImg, @@ -18,16 +18,19 @@ import { import { disconnectWallet, getWalletsWithConnectedWebsites } from '../pages/connectedWebsitesPage'; import { getTransactionFee, - overviewTabButton, - getTransactionAmount, - utxoAddressesTabButton, + detailsTabButton, + getTransactionSentAmount, + utxosTabButton, getUTXOAddresses, - transactionFeeTitle, cancelButton, transactionTotalAmountField, + transactionFeeText, } from '../pages/connector-signingTxPage'; import { getSigningData, signMessageTitle } from '../pages/connector-signingDataPage'; -import { addCollateralTitle } from '../pages/connector-getCollateralPage'; +import { + addCollateralTitle, + getCollateralTransactionFee, +} from '../pages/connector-getCollateralPage'; import { mockDAppName, extensionTabName, popupConnectorName } from '../support/windowManager'; import { connectorButton } from '../pages/sidebarPage'; import { @@ -107,25 +110,23 @@ Then(/^There is no the connector popup$/, async function () { Then( /^I select the only wallet named (.+) with ([0-9.]+) balance$/, - async function (walletName, expectedBalance) { + async function (expectedWalletName, expectedBalance) { this.webDriverLogger.info( - `Step: I select the only wallet named ${walletName} with ${expectedBalance} balance` + `Step: I select the only wallet named ${expectedWalletName} with ${expectedBalance} balance` ); const wallets = await getWallets(this); expect(wallets.length).to.equal(1, `expect 1 wallet but get ${wallets.length}`); - const name = await getWalletName(wallets, 0); - expect(name).to.equal( - walletName, - `expect wallet name ${walletName} but get wallet name ${name}` + const { walletName } = await getWalletNameAndPlate(wallets, 0); + expect(walletName).to.equal( + expectedWalletName, + `expect wallet name ${expectedWalletName} but get wallet name ${walletName}` ); const balance = await getWalletBalance(wallets, 0); - const match = balance.match(/^[0-9.]+/); - expect(match, 'Can not get wallet balance').to.not.be.null; - // $FlowFixMe[incompatible-use] - const balanceMatch = match[0]; - expect(balanceMatch).to.equal( + expect(balance, 'Can not get wallet balance').to.not.be.null; + const realBalanceDigitsOnly = balance.split(' ')[0]; + expect(realBalanceDigitsOnly).to.equal( expectedBalance, - `expect wallet balance ${expectedBalance} but get ${balanceMatch}` + `expect wallet balance ${expectedBalance} but get ${realBalanceDigitsOnly}` ); await selectWallet(wallets, 0); await this.driver.sleep(1000); @@ -179,6 +180,7 @@ Then(/^The dApp should see balance (\d+)$/, async function (expectedBalance) { }); When(/^I request signing the transaction:$/, async function (table) { + this.webDriverLogger.info(`Step: I request signing the transaction`); const fields = table.hashes()[0]; const normalizedAmount = `${parseFloat(fields.amount) * parseFloat('1000000')}`; this.webDriverLogger.info( @@ -188,35 +190,30 @@ When(/^I request signing the transaction:$/, async function (table) { }); Then(/^I should see the transaction amount data:$/, async function (table) { - await this.waitForElement(overviewTabButton); const fields = table.hashes()[0]; - const realFee = await getTransactionFee(this); - const expectedFee = `-${fields.fee}`; - const realFullAmount = await getTransactionAmount(this); - const expectedTotalAmount = `-${parseFloat(fields.amount) + parseFloat(fields.fee)}`; + this.webDriverLogger.info( - `Step: I should see the transaction amount data: amount: ${expectedTotalAmount}, fee: ${expectedFee} ` + `Step: I should see the transaction amount data: amount: ${fields.amount}, fee: ${fields.fee} ` ); - expect(realFee, 'Fee is different').to.equal(expectedFee); - expect(realFullAmount, 'Total amount is different').to.equal(expectedTotalAmount); + await this.waitForElement(detailsTabButton); + const realFee = await getTransactionFee(this); + const realSentAmount = await getTransactionSentAmount(this); + expect(realFee, 'Fee is different').to.equal(fields.fee); + expect(realSentAmount, 'Sent amount is different').to.equal(fields.amount); }); Then(/^I should see the transaction addresses info:$/, async function (table) { - await this.waitForElement(overviewTabButton); - const tableHashes = table.hashes(); - const fields = tableHashes[0]; + const fields = table.hashes()[0]; this.webDriverLogger.info( `Step: I should see the transaction addresses info: from: ${fields.fromAddress}, to: ${fields.toAddress} ` ); - - await this.click(utxoAddressesTabButton); - + await this.waitForElement(detailsTabButton); + await this.click(utxosTabButton); const expectedFromAddress = fields.fromAddress; const expectedFromAddressAmount = fields.fromAddressAmount; const expectedToAddress = fields.toAddress; const expectedToAddressAmount = fields.toAddressAmount; - const realAddresses = await getUTXOAddresses(this); const realFromAddresses = realAddresses.fromAddresses; const foundFromAddresses = realFromAddresses.filter( @@ -241,8 +238,8 @@ Then(/^I should see the transaction addresses info:$/, async function (table) { address: ${expectedFromAddress}, amount: ${expectedFromAddressAmount} Received:\n${JSON.stringify(realFromAddresses)}` ).to.equal(1); - await this.click(overviewTabButton); - await this.waitForElement(transactionFeeTitle); + await this.click(detailsTabButton); + await this.waitForElement(transactionFeeText); }); Then(/^The signing transaction API should return (.+)$/, async function (txHex) { @@ -358,19 +355,17 @@ Then(/^I cancel signing the transaction$/, async function () { }); When(/^I request signing the data:$/, async function (table) { - const tableHashes = table.hashes(); - const fields = tableHashes[0]; + const fields = table.hashes()[0]; const payload = fields.payload; this.webDriverLogger.info(`Step: I request signing the data: ${payload}`); await this.mockDAppPage.requestSigningData(payload); }); Then(/^I should see the data to sign:$/, async function (table) { - const tableHashes = table.hashes(); - const fields = tableHashes[0]; + const fields = table.hashes()[0]; const payload = fields.payload; - const actualSigningData = await getSigningData(this); this.webDriverLogger.info(`Step: I should see the data to sign: ${payload}`); + const actualSigningData = await getSigningData(this); expect(actualSigningData, 'Signing Data is different').to.equal(payload); }); @@ -417,6 +412,9 @@ Then( Then(/^The dApp should receive collateral$/, async function (table) { const fields = table.hashes()[0]; + this.webDriverLogger.info( + `Step: The dApp should receive collateral:\namount - ${fields.amount}, receiver - ${fields.receiver}` + ); const collateralResponse = (await this.mockDAppPage.getCollateralResult(): DAppConnectorResponse); expect(collateralResponse.success).to.equal(true); const collateralUtxuJson = collateralResponse.retValue[0]; @@ -431,63 +429,10 @@ Then(/^I should see the connector popup to Add Collateral with fee info$/, async await connectorPopUpIsDisplayed(this); await this.waitForElement(addCollateralTitle); const fields = table.hashes()[0]; - const realFee = await getTransactionFee(this); + const realFee = await getCollateralTransactionFee(this); expect(realFee, 'Fee is different').to.equal(fields.fee); }); -Then(/^I should see the collateral fee data:$/, async function (table) { - await this.waitForElement(overviewTabButton); - const fields = table.hashes()[0]; - const realFee = await getTransactionFee(this); - const expectedFee = `-${fields.fee}`; - const realFullAmount = await getTransactionAmount(this); - this.webDriverLogger.info(`Step: I should see the collateral fee data: ${expectedFee}`); - expect(realFee, 'Fee is different').to.equal(expectedFee); - expect(realFullAmount, 'Total amount is different').to.equal(expectedFee); -}); - -Then(/^I should see the collateral from address info:$/, async function (table) { - await this.waitForElement(overviewTabButton); - const tableHashes = table.hashes(); - const fields = tableHashes[0]; - await this.click(utxoAddressesTabButton); - - const expectedFromAddress = fields.fromAddress; - const expectedFromAddressAmount = fields.fromAddressAmount; - - const actualAddresses = await getUTXOAddresses(this); - const actualFromAddresses = actualAddresses.fromAddresses; - const foundFromAddresses = actualFromAddresses.filter( - addr => - addr.address === expectedFromAddress && addr.amount === parseFloat(expectedFromAddressAmount) - ); - this.webDriverLogger.info( - `Step: I should see the collateral from address info: address: ${expectedFromAddress}, amount: ${expectedFromAddressAmount}` - ); - expect( - foundFromAddresses.length, - `Expected fromAddress: - address:${expectedFromAddress}, amount: ${expectedFromAddressAmount} - Received:\n${JSON.stringify(actualFromAddresses)}` - ).to.equal(1); -}); - -Then(/^I should see the collateral to addresses info:$/, async function (table) { - this.webDriverLogger.info(`Step: I should see the collateral to addresses info`); - await this.waitForElement(overviewTabButton); - const tableHashes = table.hashes(); - await this.click(utxoAddressesTabButton); - - const actualAddresses = await getUTXOAddresses(this); - const actualToAddresses = actualAddresses.toAddresses; - actualToAddresses.forEach((addr, index) => { - expect(addr.address).to.equal(tableHashes[index].toAddresses); - expect(addr.amount).to.equal(parseFloat(tableHashes[index].toAddressesAmount)); - }); - await this.click(overviewTabButton); - await this.waitForElement(transactionFeeTitle); -}); - When(/^I request unused addresses$/, async function () { this.webDriverLogger.info(`Step: I request unused addresses`); await this.mockDAppPage.requestUnusedAddresses(); @@ -499,7 +444,7 @@ When(/^I request used addresses$/, async function () { }); When(/^The collateral received the error:$/, async function (table) { - this.webDriverLogger.info(`Step: I should see the collateral to addresses info`); + this.webDriverLogger.info(`Step: The collateral received the error`); const tableHashes = table.hashes(); const fields = tableHashes[0]; diff --git a/packages/yoroi-extension/features/step_definitions/trezor-steps.js b/packages/yoroi-extension/features/step_definitions/trezor-steps.js index ec687af851..bac13255c9 100644 --- a/packages/yoroi-extension/features/step_definitions/trezor-steps.js +++ b/packages/yoroi-extension/features/step_definitions/trezor-steps.js @@ -14,14 +14,17 @@ import { testWallets } from '../mock-chain/TestWallets'; import { errorBlockComponent } from '../pages/commonDialogPage'; export async function switchToTrezorAndAllow(customWorld: any) { - // wait for a new tab + // wait for a new Trezor tab and switch to it await customWorld.windowManager.findNewWindowAndSwitchTo(trezorConnectTabName); - // tick the checkbox on the Trezor page and press Allow button await customWorld.driver.sleep(1000); + // tick the checkbox Don't ask again await customWorld.waitForElement(dontAskAgainCheckbox); await customWorld.click(dontAskAgainCheckbox); + // press the Allow button await customWorld.waitForElement(confirmUsingTrezorButton); - await customWorld.click(confirmUsingTrezorButton); + // this dirty trick is necessary because the button Allow is covered by the pop-up + // which is I can't find and close from the UI side + await customWorld.clickByScript(confirmUsingTrezorButton); } export async function switchToTrezorAndExport(customWorld: any) { @@ -30,12 +33,17 @@ export async function switchToTrezorAndExport(customWorld: any) { // tick the checkbox on the Trezor page and press Allow button await customWorld.driver.sleep(1000); await customWorld.waitForElement(confirmUsingTrezorButton); - await customWorld.click(confirmUsingTrezorButton); + // this dirty trick is necessary because the button Allow is covered by the pop-up + // which is I can't find and close from the UI side + await customWorld.clickByScript(confirmUsingTrezorButton); } export async function allowPubKeysAndSwitchToYoroi(customWorld: any) { // press the Export button - await customWorld.click(exportTrezorButton); + await customWorld.waitForElement(exportTrezorButton); + // this dirty trick is necessary because the button Export is covered by the pop-up + // which is I can't find and close from the UI side + await customWorld.clickByScript(exportTrezorButton); // wait for closing the new tab await customWorld.windowManager.waitForClosingAndSwitchTo(trezorConnectTabName, extensionTabName); } diff --git a/packages/yoroi-extension/features/step_definitions/wallet-creation-steps.js b/packages/yoroi-extension/features/step_definitions/wallet-creation-steps.js index 61e2395723..6c18d0e264 100644 --- a/packages/yoroi-extension/features/step_definitions/wallet-creation-steps.js +++ b/packages/yoroi-extension/features/step_definitions/wallet-creation-steps.js @@ -7,9 +7,6 @@ import { expect } from 'chai'; import { checkErrorByTranslationId } from './common-steps'; import { clearButton, - createNormalWalletButton, - createOptionDialog, - createPaperWalletButton, createPersonalWalletButton, createWalletButton, createWalletNameError, @@ -39,15 +36,6 @@ When(/^I select the currency ([^"]*)$/, async function (currency) { await this.click(getCurrencyButton(currency)); }); -When(/^I select Create Wallet$/, async function () { - await this.waitForElement(createOptionDialog); - await this.click(createNormalWalletButton); -}); -When(/^I select Paper Wallet$/, async function () { - await this.waitForElement(createOptionDialog); - await this.click(createPaperWalletButton); -}); - When(/^I enter the created wallet password:$/, async function (table) { const fields = table.hashes()[0]; await this.input(createWalletPasswordInput, fields.password); diff --git a/packages/yoroi-extension/features/step_definitions/wallet-paper-steps.js b/packages/yoroi-extension/features/step_definitions/wallet-paper-steps.js deleted file mode 100644 index 3399f6bcb6..0000000000 --- a/packages/yoroi-extension/features/step_definitions/wallet-paper-steps.js +++ /dev/null @@ -1,62 +0,0 @@ -// @flow - -import { Given, Then } from 'cucumber'; -import { expect } from 'chai'; -import { truncateAddress } from '../../app/utils/formatters'; -import { enterRecoveryPhrase } from '../pages/restoreWalletPage'; -import { primaryButton } from '../pages/commonDialogPage'; -import { - addressElement, - getAddressesAmountButton, - paperWalletDialogSelect, -} from '../pages/newWalletPages'; -import { fakeAddresses, halfSecond } from '../support/helpers/common-constants'; - -// ========== Paper wallet ========== - -Then(/^I open Number of Addresses selection dropdown$/, async function () { - await this.click(paperWalletDialogSelect); -}); - -Then(/^I select 2 addresses$/, async function () { - await this.click(getAddressesAmountButton('2')); - await this.driver.sleep(halfSecond); -}); - -Then(/^I click the create paper wallet button$/, async function () { - await this.click(primaryButton); -}); - -Then(/^I enter the paper recovery phrase$/, async function () { - /** - * Mnemomic is printed on the paper wallet and not present in the UI - * So we instead fetch the paper wallet from app memory - */ - const recoveryPhrase = await this.driver.executeScript(() => ( - window.yoroi.stores.substores.ada.paperWallets.paper.scrambledWords - )); - - await enterRecoveryPhrase(this, recoveryPhrase.join(' ')); -}); - -Given(/^I swap the paper wallet addresses$/, async function () { - // make sure 2 addresses we generated as expected - const addresses = await this.driver.executeScript(() => ( - window.yoroi.stores.substores.ada.paperWallets.paper.addresses - )); - expect(addresses.length).to.be.equal(2); - - // we swap out the generated addresses with fake ones to get a consistent UI for screenshots - await this.driver.executeScript((fakes) => { - window.yoroi.stores.substores.ada.paperWallets.paper.addresses = fakes; - }, fakeAddresses); -}); - -Then(/^I should see two addresses displayed$/, async function () { - const addressesElem = await this.findElements(addressElement); - expect(addressesElem.length).to.be.equal(fakeAddresses.length); - for (let i = 0; i < fakeAddresses.length; i++) { - const address = await addressesElem[i].getText(); - expect(address).to.be.equal(truncateAddress(fakeAddresses[i])); - } -}); diff --git a/packages/yoroi-extension/features/step_definitions/wallet-restoration-steps.js b/packages/yoroi-extension/features/step_definitions/wallet-restoration-steps.js index c353fb19db..1f77259812 100644 --- a/packages/yoroi-extension/features/step_definitions/wallet-restoration-steps.js +++ b/packages/yoroi-extension/features/step_definitions/wallet-restoration-steps.js @@ -11,7 +11,6 @@ import { confirmButton, errorInvalidRecoveryPhrase, getWords, - paperPasswordInput, recoveryPhraseField, repeatPasswordInput, walletPasswordInput, @@ -20,14 +19,12 @@ import { masterKeyInput } from '../pages/walletClaimTransferPage'; import { byronEraButton, pickUpCurrencyDialog, - pickUpCurrencyDialogCardano, recoveryPhraseDeleteIcon, recoveryPhraseError, restoreWalletButton, restore24WordWallet, restoreDialogButton, restoreNormalWallet, - restorePaperWalletButton, shelleyEraButton, walletAlreadyExistsComponent, walletRestoreDialog, @@ -64,18 +61,6 @@ Then(/^I select bip44 15-word wallet$/, async function () { await this.waitForElement(walletRestoreDialog); }); -When(/^I click the restore paper wallet button$/, async function () { - await this.click(restoreWalletButton); - - await this.waitForElement(pickUpCurrencyDialog); - await this.click(pickUpCurrencyDialogCardano); - - await this.waitForElement(walletRestoreOptionDialog); - - await this.click(restorePaperWalletButton); - await this.waitForElement(walletRestoreDialog); -}); - When(/^I enter the recovery phrase:$/, async function (table) { const fields = table.hashes()[0]; await enterRecoveryPhrase(this, fields.recoveryPhrase); @@ -129,10 +114,6 @@ Then(/^I repeat the wallet password "([^"]*)"$/, async function (password) { await this.input(repeatPasswordInput, password); }); -When(/^I enter the paper wallet password "([^"]*)"$/, async function (password) { - await this.input(paperPasswordInput, password); -}); - When(/^I clear the restored wallet password ([^"]*)$/, async function (password) { await this.clearInputUpdatingForm(walletPasswordInput, password.length); }); diff --git a/packages/yoroi-extension/features/support/webdriver.js b/packages/yoroi-extension/features/support/webdriver.js index b18e32cd80..f8447c88c9 100644 --- a/packages/yoroi-extension/features/support/webdriver.js +++ b/packages/yoroi-extension/features/support/webdriver.js @@ -19,6 +19,10 @@ import { const fs = require('fs'); +const firefoxBin = process.env.FIREFOX_BIN + ? process.env.FIREFOX_BIN + : '/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox-bin'; + function encode(file) { return fs.readFileSync(file, { encoding: 'base64' }); } @@ -85,7 +89,7 @@ function getFirefoxBuilder() { * For Firefox it is needed to use "Firefox for Developers" to load the unsigned extensions * Set the FIREFOX_DEV env variable to the "Firefix for Developers" executable */ - .setBinary(process.env.FIREFOX_DEV) + .setBinary(firefoxBin) .addExtensions(path.resolve(__dirname, '../../Yoroi.xpi')) /** * Firefox disallows unsigned extensions by default. We solve this through a config change @@ -367,21 +371,40 @@ function CustomWorld(cmdInput: WorldInput) { }, index); }; - this.clickElementByQuery = async query => { - await this.driver.executeScript(`document.querySelector('${query}').click()`); + this.clickByScript = async (locator: LocatorObject) => { + this.webDriverLogger.info(`Webdriver: Clicking with executeScript on "${JSON.stringify(locator)}"`); + const element = await this.getElementBy(locator); + await this.driver.executeScript(`arguments[0].click()`, element); }; this.checkIfExists = async (locator: LocatorObject) => { this.webDriverLogger.info(`Webdriver: Checking if element exists "${JSON.stringify(locator)}"`); - return await this.driver.findElement(getMethod(locator.method)(locator.locator)).then( - () => true, - err => { - if (err instanceof error.NoSuchElementError) { - return false; + const state = this.driver + .findElement(getMethod(locator.method)(locator.locator)) + .then( + (response) => { + this.webDriverLogger.info(`Webdriver:checkIfExists: Response is received: ${response}`); + this.webDriverLogger.info(`Webdriver:checkIfExists: The element "${JSON.stringify(locator)}" exists`); + return true; + }, + (err) => { + if (err instanceof error.NoSuchElementError) { + this.webDriverLogger.info(`Webdriver:checkIfExists: The element "${JSON.stringify(locator)}" does not exists`); + return false; + } + promise.rejected(err); // some other error } - promise.rejected(err); // some other error - } - ); + ).catch( + (err) => { + if (err instanceof error.NoSuchElementError){ + this.webDriverLogger.info(`Webdriver:checkIfExists: The element "${JSON.stringify(locator)}" does not exists`); + return false; + } + throw(err) + } + ) + + return state; }; this.customWaiter = async ( diff --git a/packages/yoroi-extension/features/transactions.feature b/packages/yoroi-extension/features/transactions.feature index c2b6b3d667..0c31266cb9 100644 --- a/packages/yoroi-extension/features/transactions.feature +++ b/packages/yoroi-extension/features/transactions.feature @@ -277,63 +277,6 @@ Feature: Send transaction Then I submit the wallet send form Then I should see an delegation incorrect wallet password error message - @it-162 - Scenario Outline: Send from an ergo wallet (IT-162) - Given There is an Ergo wallet stored named ergo-simple-wallet - And I have an ERGO wallet with funds - When I go to the send transaction screen - And I fill the form: - | address | amount | - |
| | - And The transaction fees are "" - And I click on the next button in the wallet send form - And I see send money confirmation dialog - And I see CONFIRM TRANSACTION Pop up: - | address | amount |fee | isErgo | - |
| | | 1 | - And I enter the wallet password: - | password | - | asdfasdfasdf | - And I submit the wallet send form - Then I should see the successfully sent page - And I click the transaction page button - Then I should see the summary screen - - Examples: - | address | amount |fee | - | 9guxMsa2S1Z4xzr5JHUHZesznThjZ4BMM9Ra5Lfx2E9duAnxEmv | 5.000000000 |0.001100000 | - - @it-163 - Scenario: Send all from an ergo wallet (IT-163) - When I click the restore button for ergo - Then I select bip44 15-word wallet - And I enter the name "Restored Wallet" - And I enter the recovery phrase: - | recoveryPhrase | - | eight country switch draw meat scout mystery blade tip drift useless good keep usage title | - And I enter the restored wallet password: - | password | repeatedPassword | - | asdfasdfasdf | asdfasdfasdf | - And I click the "Restore Wallet" button - Then I should see a plate CXTP-1821 - Then I click the next button - Then I should see the opened wallet with name "Restored Wallet" - When I go to the send transaction screen - And I fill the address of the form: - | address | - | 9guxMsa2S1Z4xzr5JHUHZesznThjZ4BMM9Ra5Lfx2E9duAnxEmv | - And I open the amount dropdown and select send all - And The transaction fees are "0.001100000" - And I click on the next button in the wallet send form - And I see send money confirmation dialog - And I enter the wallet password: - | password | - | asdfasdfasdf | - And I submit the wallet send form - Then I should see the successfully sent page - And I click the transaction page button - Then I should see the summary screen - @it-164 Scenario Outline: Can receive & send funds from enterprise address (IT-164) Given There is a Shelley wallet stored named shelley-enterprise @@ -386,56 +329,6 @@ Feature: Send transaction Then I should see the summary screen And I should see 1 pending transactions - @it-170 - Scenario Outline: Can send some of a custom token (IT-170) - Given There is an Ergo wallet stored named ergo-token-wallet - And I have an ERGO wallet with funds - When I go to the send transaction screen - And I open the token selection dropdown - And I select token "USD" - And I fill the form: - | address | amount | - |
| | - And The transaction fees are "" - And I click on the next button in the wallet send form - And I see send money confirmation dialog - And I see CONFIRM TRANSACTION Pop up: - | address | amount |fee | isErgo | - |
| 0.010000000 | | 1 | - And I enter the wallet password: - | password | - | asdfasdfasdf | - And I submit the wallet send form - Then I should see the successfully sent page - And I click the transaction page button - Then I should see the summary screen - - Examples: - | address | amount | fee | - | 9guxMsa2S1Z4xzr5JHUHZesznThjZ4BMM9Ra5Lfx2E9duAnxEmv | 123 |0.001100000 | - - @it-171 - Scenario: Can send all of a custom token (IT-171) - Given There is an Ergo wallet stored named ergo-token-wallet - And I have an ERGO wallet with funds - When I go to the send transaction screen - And I open the token selection dropdown - And I select token "USD" - And I fill the address of the form: - | address | - | 9guxMsa2S1Z4xzr5JHUHZesznThjZ4BMM9Ra5Lfx2E9duAnxEmv | - And I open the amount dropdown and select send all - And The transaction fees are "0.001100000" - And I click on the next button in the wallet send form - And I see send money confirmation dialog - And I enter the wallet password: - | password | - | asdfasdfasdf | - And I submit the wallet send form - Then I should see the successfully sent page - And I click the transaction page button - Then I should see the summary screen - @it-178 Scenario Outline: Can send some of a custom Cardano token (IT-178) Given There is a Shelley wallet stored named cardano-token-wallet diff --git a/packages/yoroi-extension/features/wallet-creation.feature b/packages/yoroi-extension/features/wallet-creation.feature index dff1d6b4e8..0972a8f349 100644 --- a/packages/yoroi-extension/features/wallet-creation.feature +++ b/packages/yoroi-extension/features/wallet-creation.feature @@ -9,7 +9,6 @@ Feature: Wallet creation Scenario: Wallet creation (IT-5) When I click the create button Then I select the currency cardano - Then I select Create Wallet And I enter the name "Created Wallet" And I enter the created wallet password: | password | repeatedPassword | @@ -23,7 +22,6 @@ Feature: Wallet creation Scenario Outline: Wallet can't be created if its password doesn't meet complexity requirements (IT-7) When I click the create button Then I select the currency cardano - Then I select Create Wallet And I enter the name "Created Wallet" And I enter the created wallet password: | password | repeatedPassword | @@ -41,7 +39,6 @@ Feature: Wallet creation Scenario: Wallet access after browser restart (IT-9) When I click the create button Then I select the currency cardano - Then I select Create Wallet And I enter the name "Created Wallet" And I enter the created wallet password: | password | repeatedPassword | @@ -57,7 +54,6 @@ Feature: Wallet creation Scenario Outline: Wallet can't be created if wallet name doesn't meet requirements (IT-16) When I click the create button Then I select the currency cardano - Then I select Create Wallet And I enter the name "Created Wallet" And I enter the created wallet password: | password | repeatedPassword | @@ -79,7 +75,6 @@ Feature: Wallet creation Scenario: Mnemonic words can be cleared by clicking "Clear button" on wallet creation screen (IT-18) When I click the create button Then I select the currency cardano - Then I select Create Wallet And I enter the name "Created Wallet" And I enter the created wallet password: | password | repeatedPassword | @@ -94,7 +89,6 @@ Feature: Wallet creation Scenario: Wallet can't be created without entering password (IT-24) When I click the create button Then I select the currency cardano - Then I select Create Wallet And I enter the name "Created Wallet" And I enter the created wallet password: | password | repeatedPassword | @@ -109,7 +103,6 @@ Feature: Wallet creation Scenario: Users will be presented with a security warning prior to seed creation (IT-27) When I click the create button Then I select the currency cardano - Then I select Create Wallet And I enter the name "Created Wallet" And I enter the created wallet password: | password | repeatedPassword | @@ -117,18 +110,4 @@ Feature: Wallet creation And I click the "Create personal wallet" button Then I see the security warning prior: | message | - | wallet.backup.privacy.warning.dialog.checkbox.label.nobodyWatching | - - @it-131 - Scenario: Wallet creation. Ergo (IT-131) - When I click the create button - Then I select the currency ergo - Then I select Create Wallet - And I enter the name "Created Wallet" - And I enter the created wallet password: - | password | repeatedPassword | - | asdfasdfasdf | asdfasdfasdf | - And I click the "Create personal wallet" button - And I accept the creation terms - And I copy and enter the displayed mnemonic phrase - Then I should see the opened wallet with name "Created Wallet" + | wallet.backup.privacy.warning.dialog.checkbox.label.nobodyWatching | \ No newline at end of file diff --git a/packages/yoroi-extension/features/wallet-paper-creation.feature b/packages/yoroi-extension/features/wallet-paper-creation.feature deleted file mode 100644 index 964f985806..0000000000 --- a/packages/yoroi-extension/features/wallet-paper-creation.feature +++ /dev/null @@ -1,26 +0,0 @@ -Feature: Wallet Paper creation - - Background: - Given I have opened the extension - And I have completed the basic setup - - @it-77 - Scenario: Paper wallet creation (IT-77) - When I click the create button - Then I select the currency cardano - Then I select Paper Wallet - Then I open Number of Addresses selection dropdown - And I select 2 addresses - Then I click the create paper wallet button - Then I enter the paper wallet password "cool password" - And I repeat the wallet password "cool password" - Then I click the next button - # wait for paper wallet generation then go to next - Then I click the next button - And I enter the paper recovery phrase - And I enter the paper wallet password "cool password" - # swap addresses for UI testing - Given I swap the paper wallet addresses - Then I click then button labeled "Verify wallet" - Then I should see two addresses displayed - Then I click the next button \ No newline at end of file diff --git a/packages/yoroi-extension/features/wallet-restoration.feature b/packages/yoroi-extension/features/wallet-restoration.feature index 4cdf961fb7..2fac78e138 100644 --- a/packages/yoroi-extension/features/wallet-restoration.feature +++ b/packages/yoroi-extension/features/wallet-restoration.feature @@ -104,27 +104,6 @@ Feature: Restore Wallet | recoveryPhrase | | | remind style lunch result accuse upgrade atom eight limit glance frequent eternal fashion borrow monster galaxy | 16-words phrase | - @it-72 - Scenario: Restoring a paper wallet (IT-72) - When I click the restore paper wallet button - And I enter the name "Restored Wallet" - And I enter the recovery phrase: - | recoveryPhrase | - | mushroom expose slogan wagon uphold train absurd fix snake unable rescue curious escape member resource garbage enemy champion airport matrix year | - And I enter the paper wallet password "cool password" - And I enter the restored wallet password: - | password | repeatedPassword | - | asdfasdfasdf | asdfasdfasdf | - And I click the "Restore Wallet" button - Then I should see a plate KOTZ-1730 - Then I click the next button - Then I should see the opened wallet with name "Restored Wallet" - And I go to the receive screen - And I should see the addresses exactly list them - | address | - | Ae2tdPwUPEZF4q7tzeXnofsXLF3yCW7mwbFVxucwoXBrfUCGXJ9yHWzwVm8 | - | Ae2tdPwUPEZ7TQpzbJZCbA5BjW4zWYFn47jKo43ouvfe4EABoCfvEjwYvJr | - @it-73 Scenario Outline: Wallet restoration Recovery Phrase with less than 15 words (IT-73) And I click the restore button for cardano @@ -234,26 +213,6 @@ Feature: Restore Wallet Then I switch to "many-tx-wallet" from the dropdown Then I should see the opened wallet with name "many-tx-wallet" - @it-130 - Scenario: Restoring an ergo wallet (IT-130) - When I click the restore button for ergo - Then I select bip44 15-word wallet - And I enter the name "Restored Wallet" - And I enter the recovery phrase: - | recoveryPhrase | - | eight country switch draw meat scout mystery blade tip drift useless good keep usage title | - And I enter the restored wallet password: - | password | repeatedPassword | - | asdfasdfasdf | asdfasdfasdf | - And I click the "Restore Wallet" button - Then I should see a plate CXTP-1821 - Then I click the next button - Then I should see the opened wallet with name "Restored Wallet" - And I go to the receive screen - And I should see the addresses exactly list them - | address | - | 9erND2FjDWVTgT2TWRZ9dCLueKAWjoskx6KqRmZbtvtRXEgCrja | - @it-132 Scenario: Restoring a shelley 15-word wallet (IT-132) When I click the restore button for cardano diff --git a/packages/yoroi-extension/package-lock.json b/packages/yoroi-extension/package-lock.json index df96701dd3..2803c7f99c 100644 --- a/packages/yoroi-extension/package-lock.json +++ b/packages/yoroi-extension/package-lock.json @@ -1,6 +1,6 @@ { "name": "yoroi", - "version": "4.21.1", + "version": "4.22.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/yoroi-extension/package.json b/packages/yoroi-extension/package.json index a6e29b90ac..a37a154615 100644 --- a/packages/yoroi-extension/package.json +++ b/packages/yoroi-extension/package.json @@ -1,6 +1,6 @@ { "name": "yoroi", - "version": "4.21.1", + "version": "4.22.0", "description": "Cardano ADA wallet", "scripts": { "dev:build": "rimraf dev/ && babel-node scripts/build --type=debug", diff --git a/packages/yoroi-extension/webpack/prodConfig.js b/packages/yoroi-extension/webpack/prodConfig.js index f6b1fb62bf..9dbb0ecdce 100644 --- a/packages/yoroi-extension/webpack/prodConfig.js +++ b/packages/yoroi-extension/webpack/prodConfig.js @@ -42,8 +42,8 @@ const baseProdConfig = (env /*: EnvParams */) /*: * */ => ({ }, output: { path: path.join(__dirname, '../build/js'), - filename: '[name].bundle.js', - chunkFilename: '[name].chunk.js', + filename: '[name].[contenthash].bundle.js', + chunkFilename: '[name].[contenthash].chunk.js', publicPath: env.publicPath == null ? defaultPublicPath : env.publicPath, }, plugins: [