1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 18:00:18 +01:00

fix(17542): fix fiat currency display in few txn actions (#18011)

* fix(17542): fix fiat currency display in few txn actions

* fix(17542): refactor e2e tests to change to fia via fixture builder
This commit is contained in:
Danica Shen 2023-03-08 16:05:55 +00:00 committed by PeterYinusa
parent 8c550e78e9
commit d4bc0a453b
18 changed files with 2465 additions and 1033 deletions

View File

@ -42,11 +42,6 @@ describe('Encrypt Decrypt', function () {
css: '.request-encryption-public-key__header__text',
text: 'Request encryption public key',
});
// Account balance is converted properly
const accountBalanceLabel = await driver.findElement(
'.request-encryption-public-key__balance-value',
);
assert.equal(await accountBalanceLabel.getText(), '25 ETH');
await driver.clickElement({ text: 'Provide', tag: 'button' });
await driver.waitUntilXWindowHandles(2);
windowHandles = await driver.getAllWindowHandles();
@ -99,4 +94,86 @@ describe('Encrypt Decrypt', function () {
},
);
});
it('should show balance correctly as ETH', async function () {
await withFixtures(
{
dapp: true,
fixtures: new FixtureBuilder()
.withPermissionControllerConnectedToTestDapp()
.build(),
ganacheOptions,
title: this.test.title,
},
async ({ driver }) => {
await driver.navigate();
await driver.fill('#password', 'correct horse battery staple');
await driver.press('#password', driver.Key.ENTER);
await driver.openNewPage('http://127.0.0.1:8080');
// ------ Get Encryption key and display ETH ------
await driver.clickElement('#getEncryptionKeyButton');
await driver.waitUntilXWindowHandles(3);
const windowHandles = await driver.getAllWindowHandles();
await driver.switchToWindowWithTitle(
'MetaMask Notification',
windowHandles,
);
await driver.waitForSelector({
css: '.request-encryption-public-key__header__text',
text: 'Request encryption public key',
});
// Account balance is converted properly
const accountBalanceLabel = await driver.findElement(
'.request-encryption-public-key__balance-value',
);
assert.equal(await accountBalanceLabel.getText(), '25 ETH');
},
);
});
it('should show balance correctly as Fiat', async function () {
await withFixtures(
{
dapp: true,
fixtures: new FixtureBuilder()
.withPermissionControllerConnectedToTestDapp()
.withPreferencesController({
preferences: {
useNativeCurrencyAsPrimaryCurrency: false,
},
})
.build(),
ganacheOptions,
title: this.test.title,
},
async ({ driver }) => {
await driver.navigate();
await driver.fill('#password', 'correct horse battery staple');
await driver.press('#password', driver.Key.ENTER);
await driver.clickElement('.account-menu__icon');
await driver.openNewPage('http://127.0.0.1:8080');
// ------ Get Encryption key and display ETH ------
await driver.clickElement('#getEncryptionKeyButton');
await driver.waitUntilXWindowHandles(3);
const windowHandles = await driver.getAllWindowHandles();
await driver.switchToWindowWithTitle(
'MetaMask Notification',
windowHandles,
);
await driver.waitForSelector({
css: '.request-encryption-public-key__header__text',
text: 'Request encryption public key',
});
// Account balance is converted properly
const accountBalanceLabel = await driver.findElement(
'.request-encryption-public-key__balance-value',
);
assert.equal(await accountBalanceLabel.getText(), '$42,500.00 USD');
},
);
});
});

View File

@ -22,6 +22,9 @@ import { NETWORK_TYPES } from '../../../../shared/constants/network';
import { Numeric } from '../../../../shared/modules/Numeric';
import { EtherDenomination } from '../../../../shared/constants/common';
import ConfirmPageContainerNavigation from '../confirm-page-container/confirm-page-container-navigation';
import { formatCurrency } from '../../../helpers/utils/confirm-tx.util';
import { getValueFromWeiHex } from '../../../../shared/modules/conversion.utils';
import SignatureRequestOriginalWarning from './signature-request-original-warning';
export default class SignatureRequestOriginal extends Component {
@ -45,6 +48,8 @@ export default class SignatureRequestOriginal extends Component {
hardwareWalletRequiresConnection: PropTypes.bool,
isLedgerWallet: PropTypes.bool,
nativeCurrency: PropTypes.string.isRequired,
currentCurrency: PropTypes.string.isRequired,
conversionRate: PropTypes.number,
messagesCount: PropTypes.number,
showRejectTransactionsConfirmationModal: PropTypes.func.isRequired,
cancelAll: PropTypes.func.isRequired,
@ -269,7 +274,9 @@ export default class SignatureRequestOriginal extends Component {
const {
messagesCount,
nativeCurrency,
currentCurrency,
fromAccount: { address, balance, name },
conversionRate,
} = this.props;
const { showSignatureRequestWarning } = this.state;
const { t } = this.context;
@ -277,11 +284,23 @@ export default class SignatureRequestOriginal extends Component {
const rejectNText = t('rejectRequestsN', [messagesCount]);
const currentNetwork = this.getNetworkName();
const balanceInBaseAsset = new Numeric(balance, 16, EtherDenomination.WEI)
.toDenomination(EtherDenomination.ETH)
.toBase(10)
.round(6)
.toString();
const balanceInBaseAsset = conversionRate
? formatCurrency(
getValueFromWeiHex({
value: balance,
fromCurrency: nativeCurrency,
toCurrency: currentCurrency,
conversionRate,
numberOfDecimals: 6,
toDenomination: EtherDenomination.ETH,
}),
currentCurrency,
)
: new Numeric(balance, 16, EtherDenomination.WEI)
.toDenomination(EtherDenomination.ETH)
.round(6)
.toBase(10)
.toString();
return (
<div className="request-signature__container">
@ -293,7 +312,9 @@ export default class SignatureRequestOriginal extends Component {
networkName={currentNetwork}
accountName={name}
accountBalance={balanceInBaseAsset}
tokenName={nativeCurrency}
tokenName={
conversionRate ? currentCurrency?.toUpperCase() : nativeCurrency
}
accountAddress={address}
/>
</div>

View File

@ -11,6 +11,8 @@ import {
doesAddressRequireLedgerHidConnection,
unconfirmedMessagesHashSelector,
getTotalUnapprovedMessagesCount,
getPreferences,
getCurrentCurrency,
} from '../../../selectors';
import { getAccountByAddress, valuesFor } from '../../../helpers/utils/util';
import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck';
@ -32,14 +34,19 @@ function mapStateToProps(state, ownProps) {
const isLedgerWallet = isAddressLedger(state, from);
const messagesList = unconfirmedMessagesHashSelector(state);
const messagesCount = getTotalUnapprovedMessagesCount(state);
const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state);
return {
requester: null,
requesterAddress: null,
conversionRate: conversionRateSelector(state),
mostRecentOverviewPage: getMostRecentOverviewPage(state),
hardwareWalletRequiresConnection,
isLedgerWallet,
nativeCurrency: getNativeCurrency(state),
currentCurrency: getCurrentCurrency(state),
conversionRate: useNativeCurrencyAsPrimaryCurrency
? null
: conversionRateSelector(state),
// not passed to component
allAccounts: accountsWithSendEtherInfoSelector(state),
subjectMetadata: getSubjectMetadata(state),

View File

@ -19,6 +19,9 @@ import { NETWORK_TYPES } from '../../../../shared/constants/network';
import { Numeric } from '../../../../shared/modules/Numeric';
import { EtherDenomination } from '../../../../shared/constants/common';
import ConfirmPageContainerNavigation from '../confirm-page-container/confirm-page-container-navigation';
import { formatCurrency } from '../../../helpers/utils/confirm-tx.util';
import { getValueFromWeiHex } from '../../../../shared/modules/conversion.utils';
import Footer from './signature-request-footer';
import Message from './signature-request-message';
@ -66,7 +69,7 @@ export default class SignatureRequest extends PureComponent {
siteImage: PropTypes.string,
nativeCurrency: PropTypes.string,
currentCurrency: PropTypes.string.isRequired,
useNativeCurrencyAsPrimaryCurrency: PropTypes.bool.isRequired,
conversionRate: PropTypes.number,
provider: PropTypes.object,
subjectMetadata: PropTypes.object,
unapprovedMessagesCount: PropTypes.number,
@ -161,9 +164,10 @@ export default class SignatureRequest extends PureComponent {
subjectMetadata,
nativeCurrency,
currentCurrency,
useNativeCurrencyAsPrimaryCurrency,
conversionRate,
unapprovedMessagesCount,
} = this.props;
const { t, trackEvent } = this.context;
const {
sanitizedMessage,
@ -172,15 +176,25 @@ export default class SignatureRequest extends PureComponent {
} = this.memoizedParseMessage(data);
const rejectNText = t('rejectRequestsN', [unapprovedMessagesCount]);
const currentNetwork = this.getNetworkName();
const tokenName = useNativeCurrencyAsPrimaryCurrency
? nativeCurrency
: currentCurrency?.toUpperCase();
const balanceInBaseAsset = new Numeric(balance, 16, EtherDenomination.WEI)
.toDenomination(EtherDenomination.ETH)
.round(6)
.toBase(10)
.toString();
const balanceInBaseAsset = conversionRate
? formatCurrency(
getValueFromWeiHex({
value: balance,
fromCurrency: nativeCurrency,
toCurrency: currentCurrency,
conversionRate,
numberOfDecimals: 6,
toDenomination: EtherDenomination.ETH,
}),
currentCurrency,
)
: new Numeric(balance, 16, EtherDenomination.WEI)
.toDenomination(EtherDenomination.ETH)
.round(6)
.toBase(10)
.toString();
const onSign = (event) => {
sign(event);
trackEvent({
@ -219,12 +233,17 @@ export default class SignatureRequest extends PureComponent {
return (
<div className="signature-request">
<ConfirmPageContainerNavigation />
<div className="request-signature__account">
<div
className="request-signature__account"
data-testid="request-signature-account"
>
<NetworkAccountBalanceHeader
networkName={currentNetwork}
accountName={name}
accountBalance={balanceInBaseAsset}
tokenName={tokenName}
tokenName={
conversionRate ? currentCurrency?.toUpperCase() : nativeCurrency
}
accountAddress={address}
/>
</div>

View File

@ -5,15 +5,32 @@ import mockState from '../../../../test/data/mock-state.json';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import SignatureRequest from './signature-request.component';
const baseProps = {
hardwareWalletRequiresConnection: false,
clearConfirmTransaction: () => undefined,
cancel: () => undefined,
cancelAll: () => undefined,
mostRecentOverviewPage: '/',
showRejectTransactionsConfirmationModal: () => undefined,
sign: () => undefined,
history: { push: '/' },
provider: { type: 'rpc' },
nativeCurrency: 'ABC',
currentCurrency: 'def',
fromAccount: {
address: '0x123456789abcdef',
balance: '0x346ba7725f412cbfdb',
name: 'Antonio',
},
};
describe('Signature Request Component', () => {
const store = configureMockStore()(mockState);
describe('render', () => {
let fromAddress;
let messageData;
beforeEach(() => {
fromAddress = '0x123456789abcdef';
messageData = {
domain: {
chainId: 97,
@ -62,7 +79,7 @@ describe('Signature Request Component', () => {
};
});
it('should match snapshot when useNativeCurrencyAsPrimaryCurrency is false', () => {
it('should match snapshot when we want to switch to fiat', () => {
const msgParams = {
data: JSON.stringify(messageData),
version: 'V4',
@ -70,22 +87,11 @@ describe('Signature Request Component', () => {
};
const { container } = renderWithProvider(
<SignatureRequest
hardwareWalletRequiresConnection={false}
clearConfirmTransaction={() => undefined}
cancel={() => undefined}
cancelAll={() => undefined}
mostRecentOverviewPage="/"
showRejectTransactionsConfirmationModal={() => undefined}
history={{ push: '/' }}
sign={() => undefined}
{...baseProps}
txData={{
msgParams,
}}
fromAccount={{ address: fromAddress }}
provider={{ type: 'rpc' }}
useNativeCurrencyAsPrimaryCurrency={false}
nativeCurrency="ABC"
currentCurrency="DEF"
conversionRate={1567}
/>,
store,
);
@ -93,7 +99,7 @@ describe('Signature Request Component', () => {
expect(container).toMatchSnapshot();
});
it('should match snapshot when useNativeCurrencyAsPrimaryCurrency is true', () => {
it('should match snapshot when we are using eth', () => {
const msgParams = {
data: JSON.stringify(messageData),
version: 'V4',
@ -101,22 +107,11 @@ describe('Signature Request Component', () => {
};
const { container } = renderWithProvider(
<SignatureRequest
hardwareWalletRequiresConnection={false}
clearConfirmTransaction={() => undefined}
cancel={() => undefined}
cancelAll={() => undefined}
mostRecentOverviewPage="/"
showRejectTransactionsConfirmationModal={() => undefined}
history={{ push: '/' }}
sign={() => undefined}
{...baseProps}
txData={{
msgParams,
}}
fromAccount={{ address: fromAddress }}
provider={{ type: 'rpc' }}
useNativeCurrencyAsPrimaryCurrency
nativeCurrency="ABC"
currentCurrency="DEF"
conversionRate={null}
/>,
store,
);
@ -132,19 +127,11 @@ describe('Signature Request Component', () => {
};
const { queryByTestId } = renderWithProvider(
<SignatureRequest
hardwareWalletRequiresConnection={false}
clearConfirmTransaction={() => undefined}
cancel={() => undefined}
cancelAll={() => undefined}
mostRecentOverviewPage="/"
showRejectTransactionsConfirmationModal={() => undefined}
history={{ push: '/' }}
sign={() => undefined}
{...baseProps}
txData={{
msgParams,
}}
fromAccount={{ address: fromAddress }}
provider={{ type: 'rpc' }}
conversionRate={null}
/>,
store,
);
@ -164,19 +151,11 @@ describe('Signature Request Component', () => {
};
const { queryByText } = renderWithProvider(
<SignatureRequest
hardwareWalletRequiresConnection={false}
clearConfirmTransaction={() => undefined}
cancel={() => undefined}
cancelAll={() => undefined}
mostRecentOverviewPage="/"
showRejectTransactionsConfirmationModal={() => undefined}
history={{ push: '/' }}
sign={() => undefined}
{...baseProps}
txData={{
msgParams,
}}
fromAccount={{ address: fromAddress }}
provider={{ type: 'rpc' }}
conversionRate={null}
/>,
store,
);
@ -195,19 +174,11 @@ describe('Signature Request Component', () => {
};
const { container } = renderWithProvider(
<SignatureRequest
hardwareWalletRequiresConnection={false}
clearConfirmTransaction={() => undefined}
cancel={() => undefined}
cancelAll={() => undefined}
mostRecentOverviewPage="/"
showRejectTransactionsConfirmationModal={() => undefined}
history={{ push: '/' }}
sign={() => undefined}
{...baseProps}
txData={{
msgParams,
}}
fromAccount={{ address: fromAddress }}
provider={{ type: 'rpc' }}
conversionRate={null}
/>,
store,
);
@ -225,19 +196,11 @@ describe('Signature Request Component', () => {
};
const { container } = renderWithProvider(
<SignatureRequest
hardwareWalletRequiresConnection={false}
clearConfirmTransaction={() => undefined}
cancel={() => undefined}
cancelAll={() => undefined}
mostRecentOverviewPage="/"
showRejectTransactionsConfirmationModal={() => undefined}
history={{ push: '/' }}
sign={() => undefined}
{...baseProps}
txData={{
msgParams,
}}
fromAccount={{ address: fromAddress }}
provider={{ type: 'rpc' }}
conversionRate={null}
unapprovedMessagesCount={2}
/>,
store,
@ -256,19 +219,11 @@ describe('Signature Request Component', () => {
};
const { container } = renderWithProvider(
<SignatureRequest
hardwareWalletRequiresConnection={false}
clearConfirmTransaction={() => undefined}
cancel={() => undefined}
cancelAll={() => undefined}
mostRecentOverviewPage="/"
showRejectTransactionsConfirmationModal={() => undefined}
history={{ push: '/' }}
sign={() => undefined}
{...baseProps}
txData={{
msgParams,
}}
fromAccount={{ address: fromAddress }}
provider={{ type: 'rpc' }}
conversionRate={null}
unapprovedMessagesCount={2}
/>,
store,
@ -289,19 +244,11 @@ describe('Signature Request Component', () => {
};
const { getByText } = renderWithProvider(
<SignatureRequest
hardwareWalletRequiresConnection={false}
clearConfirmTransaction={() => undefined}
cancel={() => undefined}
cancelAll={() => undefined}
mostRecentOverviewPage="/"
showRejectTransactionsConfirmationModal={() => undefined}
history={{ push: '/' }}
sign={() => undefined}
{...baseProps}
txData={{
msgParams,
}}
fromAccount={{ address: fromAddress }}
provider={{ type: 'rpc' }}
conversionRate={null}
unapprovedMessagesCount={2}
/>,
store,

View File

@ -9,6 +9,7 @@ import {
getTotalUnapprovedMessagesCount,
getCurrentCurrency,
getPreferences,
conversionRateSelector,
} from '../../../selectors';
import {
isAddressLedger,
@ -53,7 +54,9 @@ function mapStateToProps(state, ownProps) {
mostRecentOverviewPage: getMostRecentOverviewPage(state),
nativeCurrency: getNativeCurrency(state),
currentCurrency: getCurrentCurrency(state),
useNativeCurrencyAsPrimaryCurrency,
conversionRate: useNativeCurrencyAsPrimaryCurrency
? null
: conversionRateSelector(state),
subjectMetadata: getSubjectMetadata(state),
// not forwarded to component
allAccounts: accountsWithSendEtherInfoSelector(state),
@ -91,7 +94,7 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
siteImage,
nativeCurrency,
currentCurrency,
useNativeCurrencyAsPrimaryCurrency,
conversionRate,
provider,
subjectMetadata,
unconfirmedMessagesList,
@ -145,7 +148,7 @@ function mergeProps(stateProps, dispatchProps, ownProps) {
siteImage,
nativeCurrency,
currentCurrency,
useNativeCurrencyAsPrimaryCurrency,
conversionRate,
provider,
subjectMetadata,
unapprovedMessagesCount,

View File

@ -5,73 +5,82 @@ import configureMockStore from 'redux-mock-store';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import SignatureRequest from './signature-request.container';
describe('Signature Request', () => {
const mockStore = {
metamask: {
tokenList: {
'0x514910771af9ca656af840dff83e8264ecf986ca': {
address: '0x514910771af9ca656af840dff83e8264ecf986ca',
symbol: 'LINK',
decimals: 18,
name: 'ChainLink Token',
iconUrl:
'https://crypto.com/price/coin-data/icon/LINK/color_icon.png',
aggregators: [
'Aave',
'Bancor',
'CMC',
'Crypto.com',
'CoinGecko',
'1inch',
'Paraswap',
'PMM',
'Zapper',
'Zerion',
'0x',
],
occurrences: 12,
unlisted: false,
},
const mockStoreWithEth = {
metamask: {
tokenList: {
'0x514910771af9ca656af840dff83e8264ecf986ca': {
address: '0x514910771af9ca656af840dff83e8264ecf986ca',
symbol: 'LINK',
decimals: 18,
name: 'ChainLink Token',
iconUrl: 'https://crypto.com/price/coin-data/icon/LINK/color_icon.png',
aggregators: [
'Aave',
'Bancor',
'CMC',
'Crypto.com',
'CoinGecko',
'1inch',
'Paraswap',
'PMM',
'Zapper',
'Zerion',
'0x',
],
occurrences: 12,
unlisted: false,
},
identities: {
'0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e': {
name: 'Account 2',
address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e',
},
},
addressBook: {
undefined: {
0: {
address: '0x39a4e4Af7cCB654dB9500F258c64781c8FbD39F0',
name: '',
isEns: false,
},
},
},
provider: {
type: 'rpc',
},
preferences: {
useNativeCurrencyAsPrimaryCurrency: true,
},
accounts: {
'0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5': {
address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
balance: '0x03',
},
},
cachedBalances: {},
unapprovedDecryptMsgs: {},
unapprovedEncryptionPublicKeyMsgs: {},
uncofirmedTransactions: {},
selectedAddress: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
},
};
const store = configureMockStore()(mockStore);
identities: {
'0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e': {
name: 'Account 2',
address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e',
},
},
addressBook: {
undefined: {
0: {
address: '0x39a4e4Af7cCB654dB9500F258c64781c8FbD39F0',
name: '',
isEns: false,
},
},
},
provider: {
type: 'rpc',
},
preferences: {
useNativeCurrencyAsPrimaryCurrency: true,
},
accounts: {
'0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5': {
address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
balance: '0x03',
},
},
cachedBalances: {},
unapprovedDecryptMsgs: {},
unapprovedEncryptionPublicKeyMsgs: {},
uncofirmedTransactions: {},
selectedAddress: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
nativeCurrency: 'ETH',
currentCurrency: 'usd',
conversionRate: 231.06,
},
};
const props = {
const mockStoreWithFiat = {
...mockStoreWithEth,
preferences: {
useNativeCurrencyAsPrimaryCurrency: false,
},
};
describe('Signature Request', () => {
const propsWithEth = {
fromAccount: {
address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5',
balance: '0x346ba7725f412cbfdb',
name: 'John Doe',
},
history: {
push: sinon.spy(),
@ -99,76 +108,121 @@ describe('Signature Request', () => {
time: 1,
type: 'eth_sign',
},
nativeCurrency: 'ETH',
currentCurrency: 'usd',
conversionRate: null,
};
let rerender;
const propsWithFiat = {
...propsWithEth,
conversionRate: 156.72,
};
beforeEach(() => {
rerender = renderWithProvider(
<SignatureRequest.WrappedComponent {...props} />,
store,
).rerender;
describe('Render with different currencies', () => {
it('should render balance with ETH when conversionRate is not provided', () => {
const store = configureMockStore()(mockStoreWithEth);
renderWithProvider(
<SignatureRequest.WrappedComponent {...propsWithEth} />,
store,
);
expect(
screen.getByTestId('request-signature-account').textContent,
).toMatchInlineSnapshot(
`"UUnknown private networkJohn DoeBalance966.987986 ETH"`,
);
});
it('should render balance with fiat when conversionRate not provided', () => {
const store = configureMockStore()(mockStoreWithFiat);
renderWithProvider(
<SignatureRequest.WrappedComponent {...propsWithFiat} />,
store,
);
expect(
screen.getByTestId('request-signature-account').textContent,
).toMatchInlineSnapshot(
`"UUnknown private networkJohn DoeBalance$151,546.36 USD"`,
);
});
});
afterEach(() => {
props.clearConfirmTransaction.resetHistory();
describe('functionality check', () => {
beforeEach(() => {
const store = configureMockStore()(mockStoreWithFiat);
renderWithProvider(
<SignatureRequest.WrappedComponent {...propsWithFiat} />,
store,
);
});
afterEach(() => {
propsWithFiat.clearConfirmTransaction.resetHistory();
});
it('cancel', () => {
const cancelButton = screen.getByTestId('page-container-footer-cancel');
fireEvent.click(cancelButton);
expect(propsWithFiat.cancel.calledOnce).toStrictEqual(true);
});
it('sign', () => {
const signButton = screen.getByTestId('page-container-footer-next');
fireEvent.click(signButton);
expect(propsWithFiat.sign.calledOnce).toStrictEqual(true);
});
it('cancelAll', () => {
const cancelAll = screen.getByTestId('signature-request-reject-all');
fireEvent.click(cancelAll);
expect(propsWithFiat.cancelAll.calledOnce).toStrictEqual(false);
});
it('have user warning', () => {
const warningText = screen.getByText(
'Only sign this message if you fully understand the content and trust the requesting site.',
);
expect(warningText).toBeInTheDocument();
});
});
it('cancel', () => {
const cancelButton = screen.getByTestId('page-container-footer-cancel');
describe('contract details', () => {
let store;
beforeEach(() => {
store = configureMockStore()(mockStoreWithFiat);
});
it('shows verify contract details link when verifyingContract is set', () => {
renderWithProvider(
<SignatureRequest.WrappedComponent {...propsWithFiat} />,
store,
);
const verifyingContractLink = screen.getByTestId(
'verify-contract-details',
);
expect(verifyingContractLink).toBeInTheDocument();
});
fireEvent.click(cancelButton);
it('should not show verify contract details link when verifyingContract is not set', () => {
const newData = JSON.parse(propsWithFiat.txData.msgParams.data);
delete newData.domain.verifyingContract;
expect(props.cancel.calledOnce).toStrictEqual(true);
});
it('sign', () => {
const signButton = screen.getByTestId('page-container-footer-next');
fireEvent.click(signButton);
expect(props.sign.calledOnce).toStrictEqual(true);
});
it('cancelAll', () => {
const cancelAll = screen.getByTestId('signature-request-reject-all');
fireEvent.click(cancelAll);
expect(props.cancelAll.calledOnce).toStrictEqual(false);
});
it('have user warning', () => {
const warningText = screen.getByText(
'Only sign this message if you fully understand the content and trust the requesting site.',
);
expect(warningText).toBeInTheDocument();
});
it('shows verify contract details link when verifyingContract is set', () => {
const verifyingContractLink = screen.getByTestId('verify-contract-details');
expect(verifyingContractLink).toBeInTheDocument();
});
it('does not show verify contract details link when verifyingContract is not set', () => {
const newData = JSON.parse(props.txData.msgParams.data);
delete newData.domain.verifyingContract;
const newProps = {
...props,
txData: {
...props.txData,
msgParams: {
...props.txData.msgParams,
data: JSON.stringify(newData),
const newProps = {
...propsWithFiat,
txData: {
...propsWithFiat.txData,
msgParams: {
...propsWithFiat.txData.msgParams,
data: JSON.stringify(newData),
},
},
},
};
};
rerender(<SignatureRequest.WrappedComponent {...newProps} />, store);
renderWithProvider(
<SignatureRequest.WrappedComponent {...newProps} />,
store,
);
expect(screen.queryByTestId('verify-contract-details')).toBeNull();
expect(screen.queryByTestId('verify-contract-details')).toBeNull();
});
});
});

View File

@ -0,0 +1,531 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ConfirmDecryptMessage Component should match snapshot when preference is ETH currency 1`] = `
<div>
<div
class="request-decrypt-message__container"
>
<div
class="request-decrypt-message__header"
>
<div
class="request-decrypt-message__header-background"
/>
<div
class="request-decrypt-message__header__text"
>
Decrypt request
</div>
<div
class="request-decrypt-message__header__tip-container"
>
<div
class="request-decrypt-message__header__tip"
/>
</div>
</div>
<div
class="request-decrypt-message__body"
>
<div
class="request-decrypt-message__account-info"
>
<div
class="request-decrypt-message__account"
>
<div
class="request-decrypt-message__account-text"
>
Account:
</div>
<div
class="request-decrypt-message__account-item"
>
<div
class="account-list-item undefined"
data-testid="account-list-item"
>
<div
class="account-list-item__top-row"
>
<div
class=""
>
<div
class="identicon account-list-item__identicon"
style="height: 18px; width: 18px; border-radius: 9px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 18px; height: 18px; display: inline-block; background: rgb(245, 228, 0);"
>
<svg
height="18"
width="18"
x="0"
y="0"
>
<rect
fill="#F2BE02"
height="18"
transform="translate(3.0840328880287724 -2.9223901886104127) rotate(387.1 9 9)"
width="18"
x="0"
y="0"
/>
<rect
fill="#01778E"
height="18"
transform="translate(-1.465568967274283 9.396341018731759) rotate(227.4 9 9)"
width="18"
x="0"
y="0"
/>
<rect
fill="#C81435"
height="18"
transform="translate(10.107951098008673 -7.083365091692127) rotate(422.3 9 9)"
width="18"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="account-list-item__account-name"
>
Antonio
</div>
<div
class="account-mismatch-warning__tooltip-wrapper"
>
<div
aria-describedby="tippy-tooltip-1"
class="account-mismatch-warning__tooltip-container"
data-original-title="null"
data-tooltipped=""
style="display: inline;"
tabindex="0"
>
<div
class="account-mismatch-warning__tooltip-container-icon"
>
<svg
class="info-icon info-icon--warning"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.2 5.6H8.8V4H7.2V5.6ZM8 14.4C4.472 14.4 1.6 11.528 1.6 8C1.6 4.472 4.472 1.6 8 1.6C11.528 1.6 14.4 4.472 14.4 8C14.4 11.528 11.528 14.4 8 14.4ZM8 0C6.94943 0 5.90914 0.206926 4.93853 0.608964C3.96793 1.011 3.08601 1.60028 2.34315 2.34315C0.842855 3.84344 0 5.87827 0 8C0 10.1217 0.842855 12.1566 2.34315 13.6569C3.08601 14.3997 3.96793 14.989 4.93853 15.391C5.90914 15.7931 6.94943 16 8 16C10.1217 16 12.1566 15.1571 13.6569 13.6569C15.1571 12.1566 16 10.1217 16 8C16 6.94943 15.7931 5.90914 15.391 4.93853C14.989 3.96793 14.3997 3.08601 13.6569 2.34315C12.914 1.60028 12.0321 1.011 11.0615 0.608964C10.0909 0.206926 9.05058 0 8 0ZM7.2 12H8.8V7.2H7.2V12Z"
/>
</svg>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="request-decrypt-message__request-icon"
>
<div
class=""
>
<div
class="identicon"
style="height: 40px; width: 40px; border-radius: 20px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 40px; height: 40px; display: inline-block; background: rgb(245, 228, 0);"
>
<svg
height="40"
width="40"
x="0"
y="0"
>
<rect
fill="#F2BE02"
height="40"
transform="translate(6.853406417841717 -6.49420041913425) rotate(387.1 20 20)"
width="40"
x="0"
y="0"
/>
<rect
fill="#01778E"
height="40"
transform="translate(-3.2568199272761853 20.88075781940391) rotate(227.4 20 20)"
width="40"
x="0"
y="0"
/>
<rect
fill="#C81435"
height="40"
transform="translate(22.462113551130386 -15.740811314871396) rotate(422.3 20 20)"
width="40"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
</div>
<div
class="request-decrypt-message__balance"
>
<div
class="request-decrypt-message__balance-text"
>
Balance:
</div>
<div
class="request-decrypt-message__balance-value"
>
966.987986 ABC
</div>
</div>
</div>
<div
class="request-decrypt-message__visual"
>
<section>
<i
class="request-decrypt-message__visual-identicon--default"
>
T
</i>
<div
class="request-decrypt-message__notice"
>
test would like to read this message to complete your action
</div>
</section>
</div>
<div
class="request-decrypt-message__message"
>
<div
class="request-decrypt-message__message-text"
>
{"domain":{"chainId":97,"name":"Ether Mail","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","version":"1"},"message":{"contents":"Hello, Bob!","from":{"name":"Cow","wallets":["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826","0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"]},"to":[{"name":"Bob","wallets":["0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57","0xB0B0b0b0b0b0B000000000000000000000000000"]}]},"primaryType":"Mail","types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person[]"},{"name":"contents","type":"string"}],"Person":[{"name":"name","type":"string"},{"name":"wallets","type":"address[]"}]}}
</div>
<div
class="request-decrypt-message__message-cover"
/>
<div
class="request-decrypt-message__message-lock"
>
<div
class="request-decrypt-message__message-lock__container"
>
<i
class="fa fa-lock fa-lg request-decrypt-message__message-lock__container__icon"
/>
<div
class="request-decrypt-message__message-lock__container__text"
>
Decrypt message
</div>
</div>
</div>
</div>
<div />
</div>
<div
class="page-container__footer"
>
<footer>
<button
class="button btn--rounded btn-secondary page-container__footer-button page-container__footer-button__cancel"
data-testid="page-container-footer-cancel"
role="button"
tabindex="0"
>
Cancel
</button>
<button
class="button btn--rounded btn-primary page-container__footer-button"
data-testid="page-container-footer-next"
role="button"
tabindex="0"
>
Decrypt
</button>
</footer>
</div>
</div>
</div>
`;
exports[`ConfirmDecryptMessage Component should match snapshot when preference is Fiat currency 1`] = `
<div>
<div
class="request-decrypt-message__container"
>
<div
class="request-decrypt-message__header"
>
<div
class="request-decrypt-message__header-background"
/>
<div
class="request-decrypt-message__header__text"
>
Decrypt request
</div>
<div
class="request-decrypt-message__header__tip-container"
>
<div
class="request-decrypt-message__header__tip"
/>
</div>
</div>
<div
class="request-decrypt-message__body"
>
<div
class="request-decrypt-message__account-info"
>
<div
class="request-decrypt-message__account"
>
<div
class="request-decrypt-message__account-text"
>
Account:
</div>
<div
class="request-decrypt-message__account-item"
>
<div
class="account-list-item undefined"
data-testid="account-list-item"
>
<div
class="account-list-item__top-row"
>
<div
class=""
>
<div
class="identicon account-list-item__identicon"
style="height: 18px; width: 18px; border-radius: 9px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 18px; height: 18px; display: inline-block; background: rgb(245, 228, 0);"
>
<svg
height="18"
width="18"
x="0"
y="0"
>
<rect
fill="#F2BE02"
height="18"
transform="translate(3.0840328880287724 -2.9223901886104127) rotate(387.1 9 9)"
width="18"
x="0"
y="0"
/>
<rect
fill="#01778E"
height="18"
transform="translate(-1.465568967274283 9.396341018731759) rotate(227.4 9 9)"
width="18"
x="0"
y="0"
/>
<rect
fill="#C81435"
height="18"
transform="translate(10.107951098008673 -7.083365091692127) rotate(422.3 9 9)"
width="18"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="account-list-item__account-name"
>
Antonio
</div>
<div
class="account-mismatch-warning__tooltip-wrapper"
>
<div
aria-describedby="tippy-tooltip-2"
class="account-mismatch-warning__tooltip-container"
data-original-title="null"
data-tooltipped=""
style="display: inline;"
tabindex="0"
>
<div
class="account-mismatch-warning__tooltip-container-icon"
>
<svg
class="info-icon info-icon--warning"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.2 5.6H8.8V4H7.2V5.6ZM8 14.4C4.472 14.4 1.6 11.528 1.6 8C1.6 4.472 4.472 1.6 8 1.6C11.528 1.6 14.4 4.472 14.4 8C14.4 11.528 11.528 14.4 8 14.4ZM8 0C6.94943 0 5.90914 0.206926 4.93853 0.608964C3.96793 1.011 3.08601 1.60028 2.34315 2.34315C0.842855 3.84344 0 5.87827 0 8C0 10.1217 0.842855 12.1566 2.34315 13.6569C3.08601 14.3997 3.96793 14.989 4.93853 15.391C5.90914 15.7931 6.94943 16 8 16C10.1217 16 12.1566 15.1571 13.6569 13.6569C15.1571 12.1566 16 10.1217 16 8C16 6.94943 15.7931 5.90914 15.391 4.93853C14.989 3.96793 14.3997 3.08601 13.6569 2.34315C12.914 1.60028 12.0321 1.011 11.0615 0.608964C10.0909 0.206926 9.05058 0 8 0ZM7.2 12H8.8V7.2H7.2V12Z"
/>
</svg>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="request-decrypt-message__request-icon"
>
<div
class=""
>
<div
class="identicon"
style="height: 40px; width: 40px; border-radius: 20px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 40px; height: 40px; display: inline-block; background: rgb(245, 228, 0);"
>
<svg
height="40"
width="40"
x="0"
y="0"
>
<rect
fill="#F2BE02"
height="40"
transform="translate(6.853406417841717 -6.49420041913425) rotate(387.1 20 20)"
width="40"
x="0"
y="0"
/>
<rect
fill="#01778E"
height="40"
transform="translate(-3.2568199272761853 20.88075781940391) rotate(227.4 20 20)"
width="40"
x="0"
y="0"
/>
<rect
fill="#C81435"
height="40"
transform="translate(22.462113551130386 -15.740811314871396) rotate(422.3 20 20)"
width="40"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
</div>
<div
class="request-decrypt-message__balance"
>
<div
class="request-decrypt-message__balance-text"
>
Balance:
</div>
<div
class="request-decrypt-message__balance-value"
>
1520956.064158 DEF
</div>
</div>
</div>
<div
class="request-decrypt-message__visual"
>
<section>
<i
class="request-decrypt-message__visual-identicon--default"
>
T
</i>
<div
class="request-decrypt-message__notice"
>
test would like to read this message to complete your action
</div>
</section>
</div>
<div
class="request-decrypt-message__message"
>
<div
class="request-decrypt-message__message-text"
>
{"domain":{"chainId":97,"name":"Ether Mail","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","version":"1"},"message":{"contents":"Hello, Bob!","from":{"name":"Cow","wallets":["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826","0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"]},"to":[{"name":"Bob","wallets":["0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57","0xB0B0b0b0b0b0B000000000000000000000000000"]}]},"primaryType":"Mail","types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person[]"},{"name":"contents","type":"string"}],"Person":[{"name":"name","type":"string"},{"name":"wallets","type":"address[]"}]}}
</div>
<div
class="request-decrypt-message__message-cover"
/>
<div
class="request-decrypt-message__message-lock"
>
<div
class="request-decrypt-message__message-lock__container"
>
<i
class="fa fa-lock fa-lg request-decrypt-message__message-lock__container__icon"
/>
<div
class="request-decrypt-message__message-lock__container__text"
>
Decrypt message
</div>
</div>
</div>
</div>
<div />
</div>
<div
class="page-container__footer"
>
<footer>
<button
class="button btn--rounded btn-secondary page-container__footer-button page-container__footer-button__cancel"
data-testid="page-container-footer-cancel"
role="button"
tabindex="0"
>
Cancel
</button>
<button
class="button btn--rounded btn-primary page-container__footer-button"
data-testid="page-container-footer-next"
role="button"
tabindex="0"
>
Decrypt
</button>
</footer>
</div>
</div>
</div>
`;

View File

@ -15,6 +15,8 @@ import { Numeric } from '../../../shared/modules/Numeric';
import { EtherDenomination } from '../../../shared/constants/common';
import { Icon, ICON_NAMES } from '../../components/component-library';
import { IconColor } from '../../helpers/constants/design-system';
import { formatCurrency } from '../../helpers/utils/confirm-tx.util';
import { getValueFromWeiHex } from '../../../shared/modules/conversion.utils';
export default class ConfirmDecryptMessage extends Component {
static contextTypes = {
@ -38,10 +40,11 @@ export default class ConfirmDecryptMessage extends Component {
txData: PropTypes.object,
subjectMetadata: PropTypes.object,
nativeCurrency: PropTypes.string.isRequired,
currentCurrency: PropTypes.string.isRequired,
conversionRate: PropTypes.number,
};
state = {
fromAccount: this.props.fromAccount,
copyToClipboardPressed: false,
hasCopied: false,
};
@ -77,7 +80,7 @@ export default class ConfirmDecryptMessage extends Component {
};
renderAccount = () => {
const { fromAccount } = this.state;
const { fromAccount } = this.props;
const { t } = this.context;
return (
@ -94,20 +97,31 @@ export default class ConfirmDecryptMessage extends Component {
};
renderBalance = () => {
const { nativeCurrency } = this.props;
const {
conversionRate,
nativeCurrency,
currentCurrency,
fromAccount: { balance },
} = this.state;
} = this.props;
const { t } = this.context;
const nativeCurrencyBalance = new Numeric(
balance,
16,
EtherDenomination.WEI,
)
.toDenomination(EtherDenomination.ETH)
.round(6)
.toBase(10);
const nativeCurrencyBalance = conversionRate
? formatCurrency(
getValueFromWeiHex({
value: balance,
fromCurrency: nativeCurrency,
toCurrency: currentCurrency,
conversionRate,
numberOfDecimals: 6,
toDenomination: EtherDenomination.ETH,
}),
currentCurrency,
)
: new Numeric(balance, 16, EtherDenomination.WEI)
.toDenomination(EtherDenomination.ETH)
.round(6)
.toBase(10)
.toString();
return (
<div className="request-decrypt-message__balance">
@ -115,7 +129,9 @@ export default class ConfirmDecryptMessage extends Component {
{`${t('balance')}:`}
</div>
<div className="request-decrypt-message__balance-value">
{`${nativeCurrencyBalance} ${nativeCurrency}`}
{`${nativeCurrencyBalance} ${
conversionRate ? currentCurrency?.toUpperCase() : nativeCurrency
}`}
</div>
</div>
);

View File

@ -0,0 +1,130 @@
import React from 'react';
import configureMockStore from 'redux-mock-store';
import mockState from '../../../test/data/mock-state.json';
import { renderWithProvider } from '../../../test/lib/render-helpers';
import ConfirmDecryptMessage from './confirm-decrypt-message.component';
const messageData = {
domain: {
chainId: 97,
name: 'Ether Mail',
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
version: '1',
},
message: {
contents: 'Hello, Bob!',
from: {
name: 'Cow',
wallets: [
'0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
'0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
],
},
to: [
{
name: 'Bob',
wallets: [
'0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
'0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
'0xB0B0b0b0b0b0B000000000000000000000000000',
],
},
],
},
primaryType: 'Mail',
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person[]' },
{ name: 'contents', type: 'string' },
],
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallets', type: 'address[]' },
],
},
};
const baseProps = {
clearConfirmTransaction: () => undefined,
cancelDecryptMessage: () => undefined,
decryptMessage: () => undefined,
decryptMessageInline: () => undefined,
mostRecentOverviewPage: '/',
history: { push: '/' },
requesterAddress: '0x123456789abcdef',
txData: {
msgParams: {
data: JSON.stringify(messageData),
version: 'V4',
origin: 'test',
},
},
subjectMetadata: {
'peepeth.com': {
iconUrl: 'https://peepeth.com/favicon-32x32.png',
name: 'Peepeth',
},
'https://remix.ethereum.org': {
iconUrl: 'https://remix.ethereum.org/icon.png',
name: 'Remix - Ethereum IDE',
},
},
nativeCurrency: 'ABC',
currentCurrency: 'def',
fromAccount: {
address: '0x123456789abcdef',
balance: '0x346ba7725f412cbfdb',
name: 'Antonio',
},
};
describe('ConfirmDecryptMessage Component', () => {
const store = configureMockStore()(mockState);
it('should match snapshot when preference is ETH currency', () => {
const { container } = renderWithProvider(
<ConfirmDecryptMessage {...baseProps} conversionRate={null} />,
store,
);
expect(container).toMatchSnapshot();
expect(
container.querySelector('.request-decrypt-message__balance-value')
.textContent,
).toMatchInlineSnapshot(`"966.987986 ABC"`);
});
it('should match snapshot when preference is Fiat currency', () => {
const { container } = renderWithProvider(
<ConfirmDecryptMessage {...baseProps} conversionRate={1572.88} />,
store,
);
expect(container).toMatchSnapshot();
expect(
container.querySelector('.request-decrypt-message__balance-value')
.textContent,
).toMatchInlineSnapshot(`"1520956.064158 DEF"`);
});
it('should match snapshot when there is no txData', () => {
const newProps = {
...baseProps,
txData: null,
};
const { container } = renderWithProvider(
<ConfirmDecryptMessage {...newProps} conversionRate={1572.88} />,
store,
);
expect(
container.querySelector('.request-decrypt-message__container'),
).toBeNull();
});
});

View File

@ -9,6 +9,9 @@ import {
decryptMsgInline,
} from '../../store/actions';
import {
conversionRateSelector,
getCurrentCurrency,
getPreferences,
getTargetAccountWithSendEtherInfo,
unconfirmedTransactionsListSelector,
} from '../../selectors';
@ -22,6 +25,8 @@ function mapStateToProps(state) {
metamask: { subjectMetadata = {} },
} = state;
const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state);
const unconfirmedTransactions = unconfirmedTransactionsListSelector(state);
const txData = unconfirmedTransactions[0];
@ -37,8 +42,12 @@ function mapStateToProps(state) {
fromAccount,
requester: null,
requesterAddress: null,
conversionRate: useNativeCurrencyAsPrimaryCurrency
? null
: conversionRateSelector(state),
mostRecentOverviewPage: getMostRecentOverviewPage(state),
nativeCurrency: getNativeCurrency(state),
currentCurrency: getCurrentCurrency(state),
};
}

View File

@ -0,0 +1,499 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ConfirmDecryptMessage Component should match snapshot when preference is ETH currency 1`] = `
<div>
<div
class="request-encryption-public-key__container"
>
<div
class="request-encryption-public-key__header"
>
<div
class="request-encryption-public-key__header-background"
/>
<div
class="request-encryption-public-key__header__text"
>
Request encryption public key
</div>
<div
class="request-encryption-public-key__header__tip-container"
>
<div
class="request-encryption-public-key__header__tip"
/>
</div>
</div>
<div
class="request-encryption-public-key__body"
>
<div
class="request-encryption-public-key__account-info"
>
<div
class="request-encryption-public-key__account"
>
<div
class="request-encryption-public-key__account-text"
>
Account:
</div>
<div
class="request-encryption-public-key__account-item"
>
<div
class="account-list-item undefined"
data-testid="account-list-item"
>
<div
class="account-list-item__top-row"
>
<div
class=""
>
<div
class="identicon account-list-item__identicon"
style="height: 18px; width: 18px; border-radius: 9px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 18px; height: 18px; display: inline-block; background: rgb(245, 228, 0);"
>
<svg
height="18"
width="18"
x="0"
y="0"
>
<rect
fill="#F2BE02"
height="18"
transform="translate(3.0840328880287724 -2.9223901886104127) rotate(387.1 9 9)"
width="18"
x="0"
y="0"
/>
<rect
fill="#01778E"
height="18"
transform="translate(-1.465568967274283 9.396341018731759) rotate(227.4 9 9)"
width="18"
x="0"
y="0"
/>
<rect
fill="#C81435"
height="18"
transform="translate(10.107951098008673 -7.083365091692127) rotate(422.3 9 9)"
width="18"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="account-list-item__account-name"
>
Antonio
</div>
<div
class="account-mismatch-warning__tooltip-wrapper"
>
<div
aria-describedby="tippy-tooltip-1"
class="account-mismatch-warning__tooltip-container"
data-original-title="null"
data-tooltipped=""
style="display: inline;"
tabindex="0"
>
<div
class="account-mismatch-warning__tooltip-container-icon"
>
<svg
class="info-icon info-icon--warning"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.2 5.6H8.8V4H7.2V5.6ZM8 14.4C4.472 14.4 1.6 11.528 1.6 8C1.6 4.472 4.472 1.6 8 1.6C11.528 1.6 14.4 4.472 14.4 8C14.4 11.528 11.528 14.4 8 14.4ZM8 0C6.94943 0 5.90914 0.206926 4.93853 0.608964C3.96793 1.011 3.08601 1.60028 2.34315 2.34315C0.842855 3.84344 0 5.87827 0 8C0 10.1217 0.842855 12.1566 2.34315 13.6569C3.08601 14.3997 3.96793 14.989 4.93853 15.391C5.90914 15.7931 6.94943 16 8 16C10.1217 16 12.1566 15.1571 13.6569 13.6569C15.1571 12.1566 16 10.1217 16 8C16 6.94943 15.7931 5.90914 15.391 4.93853C14.989 3.96793 14.3997 3.08601 13.6569 2.34315C12.914 1.60028 12.0321 1.011 11.0615 0.608964C10.0909 0.206926 9.05058 0 8 0ZM7.2 12H8.8V7.2H7.2V12Z"
/>
</svg>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="request-encryption-public-key__request-icon"
>
<div
class=""
>
<div
class="identicon"
style="height: 40px; width: 40px; border-radius: 20px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 40px; height: 40px; display: inline-block; background: rgb(245, 228, 0);"
>
<svg
height="40"
width="40"
x="0"
y="0"
>
<rect
fill="#F2BE02"
height="40"
transform="translate(6.853406417841717 -6.49420041913425) rotate(387.1 20 20)"
width="40"
x="0"
y="0"
/>
<rect
fill="#01778E"
height="40"
transform="translate(-3.2568199272761853 20.88075781940391) rotate(227.4 20 20)"
width="40"
x="0"
y="0"
/>
<rect
fill="#C81435"
height="40"
transform="translate(22.462113551130386 -15.740811314871396) rotate(422.3 20 20)"
width="40"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
</div>
<div
class="request-encryption-public-key__balance"
>
<div
class="request-encryption-public-key__balance-text"
>
Balance:
</div>
<div
class="request-encryption-public-key__balance-value"
>
966.987986 ABC
</div>
</div>
</div>
<div
class="request-encryption-public-key__visual"
>
<section>
<i
class="request-encryption-public-key__visual-identicon--default"
>
T
</i>
<div
class="request-encryption-public-key__notice"
>
<span>
<div
class="site-origin"
>
<bdi
dir="ltr"
>
test
</bdi>
</div>
would like your public encryption key. By consenting, this site will be able to compose encrypted messages to you.
</span>
</div>
</section>
</div>
</div>
<div
class="page-container__footer"
>
<footer>
<button
class="button btn--rounded btn-secondary page-container__footer-button page-container__footer-button__cancel"
data-testid="page-container-footer-cancel"
role="button"
tabindex="0"
>
Cancel
</button>
<button
class="button btn--rounded btn-primary page-container__footer-button"
data-testid="page-container-footer-next"
role="button"
tabindex="0"
>
Provide
</button>
</footer>
</div>
</div>
</div>
`;
exports[`ConfirmDecryptMessage Component should match snapshot when preference is Fiat currency 1`] = `
<div>
<div
class="request-encryption-public-key__container"
>
<div
class="request-encryption-public-key__header"
>
<div
class="request-encryption-public-key__header-background"
/>
<div
class="request-encryption-public-key__header__text"
>
Request encryption public key
</div>
<div
class="request-encryption-public-key__header__tip-container"
>
<div
class="request-encryption-public-key__header__tip"
/>
</div>
</div>
<div
class="request-encryption-public-key__body"
>
<div
class="request-encryption-public-key__account-info"
>
<div
class="request-encryption-public-key__account"
>
<div
class="request-encryption-public-key__account-text"
>
Account:
</div>
<div
class="request-encryption-public-key__account-item"
>
<div
class="account-list-item undefined"
data-testid="account-list-item"
>
<div
class="account-list-item__top-row"
>
<div
class=""
>
<div
class="identicon account-list-item__identicon"
style="height: 18px; width: 18px; border-radius: 9px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 18px; height: 18px; display: inline-block; background: rgb(245, 228, 0);"
>
<svg
height="18"
width="18"
x="0"
y="0"
>
<rect
fill="#F2BE02"
height="18"
transform="translate(3.0840328880287724 -2.9223901886104127) rotate(387.1 9 9)"
width="18"
x="0"
y="0"
/>
<rect
fill="#01778E"
height="18"
transform="translate(-1.465568967274283 9.396341018731759) rotate(227.4 9 9)"
width="18"
x="0"
y="0"
/>
<rect
fill="#C81435"
height="18"
transform="translate(10.107951098008673 -7.083365091692127) rotate(422.3 9 9)"
width="18"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="account-list-item__account-name"
>
Antonio
</div>
<div
class="account-mismatch-warning__tooltip-wrapper"
>
<div
aria-describedby="tippy-tooltip-2"
class="account-mismatch-warning__tooltip-container"
data-original-title="null"
data-tooltipped=""
style="display: inline;"
tabindex="0"
>
<div
class="account-mismatch-warning__tooltip-container-icon"
>
<svg
class="info-icon info-icon--warning"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.2 5.6H8.8V4H7.2V5.6ZM8 14.4C4.472 14.4 1.6 11.528 1.6 8C1.6 4.472 4.472 1.6 8 1.6C11.528 1.6 14.4 4.472 14.4 8C14.4 11.528 11.528 14.4 8 14.4ZM8 0C6.94943 0 5.90914 0.206926 4.93853 0.608964C3.96793 1.011 3.08601 1.60028 2.34315 2.34315C0.842855 3.84344 0 5.87827 0 8C0 10.1217 0.842855 12.1566 2.34315 13.6569C3.08601 14.3997 3.96793 14.989 4.93853 15.391C5.90914 15.7931 6.94943 16 8 16C10.1217 16 12.1566 15.1571 13.6569 13.6569C15.1571 12.1566 16 10.1217 16 8C16 6.94943 15.7931 5.90914 15.391 4.93853C14.989 3.96793 14.3997 3.08601 13.6569 2.34315C12.914 1.60028 12.0321 1.011 11.0615 0.608964C10.0909 0.206926 9.05058 0 8 0ZM7.2 12H8.8V7.2H7.2V12Z"
/>
</svg>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="request-encryption-public-key__request-icon"
>
<div
class=""
>
<div
class="identicon"
style="height: 40px; width: 40px; border-radius: 20px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 40px; height: 40px; display: inline-block; background: rgb(245, 228, 0);"
>
<svg
height="40"
width="40"
x="0"
y="0"
>
<rect
fill="#F2BE02"
height="40"
transform="translate(6.853406417841717 -6.49420041913425) rotate(387.1 20 20)"
width="40"
x="0"
y="0"
/>
<rect
fill="#01778E"
height="40"
transform="translate(-3.2568199272761853 20.88075781940391) rotate(227.4 20 20)"
width="40"
x="0"
y="0"
/>
<rect
fill="#C81435"
height="40"
transform="translate(22.462113551130386 -15.740811314871396) rotate(422.3 20 20)"
width="40"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
</div>
<div
class="request-encryption-public-key__balance"
>
<div
class="request-encryption-public-key__balance-text"
>
Balance:
</div>
<div
class="request-encryption-public-key__balance-value"
>
1520956.064158 DEF
</div>
</div>
</div>
<div
class="request-encryption-public-key__visual"
>
<section>
<i
class="request-encryption-public-key__visual-identicon--default"
>
T
</i>
<div
class="request-encryption-public-key__notice"
>
<span>
<div
class="site-origin"
>
<bdi
dir="ltr"
>
test
</bdi>
</div>
would like your public encryption key. By consenting, this site will be able to compose encrypted messages to you.
</span>
</div>
</section>
</div>
</div>
<div
class="page-container__footer"
>
<footer>
<button
class="button btn--rounded btn-secondary page-container__footer-button page-container__footer-button__cancel"
data-testid="page-container-footer-cancel"
role="button"
tabindex="0"
>
Cancel
</button>
<button
class="button btn--rounded btn-primary page-container__footer-button"
data-testid="page-container-footer-next"
role="button"
tabindex="0"
>
Provide
</button>
</footer>
</div>
</div>
</div>
`;

View File

@ -10,6 +10,8 @@ import { EVENT } from '../../../shared/constants/metametrics';
import SiteOrigin from '../../components/ui/site-origin';
import { Numeric } from '../../../shared/modules/Numeric';
import { EtherDenomination } from '../../../shared/constants/common';
import { formatCurrency } from '../../helpers/utils/confirm-tx.util';
import { getValueFromWeiHex } from '../../../shared/modules/conversion.utils';
export default class ConfirmEncryptionPublicKey extends Component {
static contextTypes = {
@ -32,6 +34,8 @@ export default class ConfirmEncryptionPublicKey extends Component {
subjectMetadata: PropTypes.object,
mostRecentOverviewPage: PropTypes.string.isRequired,
nativeCurrency: PropTypes.string.isRequired,
currentCurrency: PropTypes.string.isRequired,
conversionRate: PropTypes.number,
};
renderHeader = () => {
@ -69,19 +73,30 @@ export default class ConfirmEncryptionPublicKey extends Component {
renderBalance = () => {
const {
conversionRate,
nativeCurrency,
currentCurrency,
fromAccount: { balance },
} = this.props;
const { t } = this.context;
const nativeCurrencyBalance = new Numeric(
balance,
16,
EtherDenomination.WEI,
)
.toDenomination(EtherDenomination.ETH)
.round(6)
.toBase(10);
const nativeCurrencyBalance = conversionRate
? formatCurrency(
getValueFromWeiHex({
value: balance,
fromCurrency: nativeCurrency,
toCurrency: currentCurrency,
conversionRate,
numberOfDecimals: 6,
toDenomination: EtherDenomination.ETH,
}),
currentCurrency,
)
: new Numeric(balance, 16, EtherDenomination.WEI)
.toDenomination(EtherDenomination.ETH)
.round(6)
.toBase(10)
.toString();
return (
<div className="request-encryption-public-key__balance">
@ -89,7 +104,9 @@ export default class ConfirmEncryptionPublicKey extends Component {
{`${t('balance')}:`}
</div>
<div className="request-encryption-public-key__balance-value">
{`${nativeCurrencyBalance} ${nativeCurrency}`}
{`${nativeCurrencyBalance} ${
conversionRate ? currentCurrency?.toUpperCase() : nativeCurrency
}`}
</div>
</div>
);

View File

@ -0,0 +1,79 @@
import React from 'react';
import configureMockStore from 'redux-mock-store';
import mockState from '../../../test/data/mock-state.json';
import { renderWithProvider } from '../../../test/lib/render-helpers';
import ConfirmEncryptionPublicKey from './confirm-encryption-public-key.component';
const baseProps = {
clearConfirmTransaction: () => undefined,
cancelEncryptionPublicKey: () => undefined,
encryptionPublicKey: () => undefined,
mostRecentOverviewPage: '/',
history: { push: '/' },
requesterAddress: '0x123456789abcdef',
txData: {
origin: 'test',
},
subjectMetadata: {
'peepeth.com': {
iconUrl: 'https://peepeth.com/favicon-32x32.png',
name: 'Peepeth',
},
'https://remix.ethereum.org': {
iconUrl: 'https://remix.ethereum.org/icon.png',
name: 'Remix - Ethereum IDE',
},
},
nativeCurrency: 'ABC',
currentCurrency: 'def',
fromAccount: {
address: '0x123456789abcdef',
balance: '0x346ba7725f412cbfdb',
name: 'Antonio',
},
};
describe('ConfirmDecryptMessage Component', () => {
const store = configureMockStore()(mockState);
it('should match snapshot when preference is ETH currency', () => {
const { container } = renderWithProvider(
<ConfirmEncryptionPublicKey {...baseProps} conversionRate={null} />,
store,
);
expect(container).toMatchSnapshot();
expect(
container.querySelector('.request-encryption-public-key__balance-value')
.textContent,
).toMatchInlineSnapshot(`"966.987986 ABC"`);
});
it('should match snapshot when preference is Fiat currency', () => {
const { container } = renderWithProvider(
<ConfirmEncryptionPublicKey {...baseProps} conversionRate={1572.88} />,
store,
);
expect(container).toMatchSnapshot();
expect(
container.querySelector('.request-encryption-public-key__balance-value')
.textContent,
).toMatchInlineSnapshot(`"1520956.064158 DEF"`);
});
it('should match snapshot when there is no txData', () => {
const newProps = {
...baseProps,
txData: null,
};
const { container } = renderWithProvider(
<ConfirmEncryptionPublicKey {...newProps} conversionRate={1572.88} />,
store,
);
expect(
container.querySelector('.request-decrypt-message__container'),
).toBeNull();
});
});

View File

@ -9,8 +9,11 @@ import {
} from '../../store/actions';
import {
conversionRateSelector,
unconfirmedTransactionsListSelector,
getTargetAccountWithSendEtherInfo,
getPreferences,
getCurrentCurrency,
} from '../../selectors';
import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm-transaction.duck';
@ -23,6 +26,8 @@ function mapStateToProps(state) {
metamask: { subjectMetadata = {} },
} = state;
const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state);
const unconfirmedTransactions = unconfirmedTransactionsListSelector(state);
const txData = unconfirmedTransactions[0];
@ -38,8 +43,12 @@ function mapStateToProps(state) {
fromAccount,
requester: null,
requesterAddress: null,
conversionRate: useNativeCurrencyAsPrimaryCurrency
? null
: conversionRateSelector(state),
mostRecentOverviewPage: getMostRecentOverviewPage(state),
nativeCurrency: getNativeCurrency(state),
currentCurrency: getCurrentCurrency(state),
};
}

View File

@ -28,6 +28,11 @@ export default {
encryptionPublicKey: {
action: 'encryptionPublicKey',
},
conversionRate: {
control: {
type: 'number',
},
},
history: {
control: {
type: 'object',
@ -69,6 +74,8 @@ export default {
subjectMetadata: metamask.subjectMetadata,
mostRecentOverviewPage: history.mostRecentOverviewPage,
nativeCurrency: metamask.nativeCurrency,
currentCurrency: metamask.currentCurrency,
conversionRate: metamask.conversionRate,
},
};

View File

@ -73,6 +73,7 @@ exports[`Signature Request Component render should match snapshot 1`] = `
</div>
<div
class="request-signature__account"
data-testid="request-signature-account"
>
<div
class="box network-account-balance-header box--padding-4 box--display-flex box--flex-direction-row box--justify-content-space-between box--align-items-center"