mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 01:39:44 +01:00
Added a 'Verify contract details' link to SetApprovalForAll confirmation screens (#15756)
This commit is contained in:
parent
a87c1750b0
commit
bf1db006fd
6
app/_locales/en/messages.json
generated
6
app/_locales/en/messages.json
generated
@ -770,6 +770,12 @@
|
||||
"contractInteraction": {
|
||||
"message": "Contract interaction"
|
||||
},
|
||||
"contractNFT": {
|
||||
"message": "NFT contract"
|
||||
},
|
||||
"contractRequestingAccess": {
|
||||
"message": "Contract requesting access"
|
||||
},
|
||||
"contractRequestingSpendingCap": {
|
||||
"message": "Contract requesting spending cap"
|
||||
},
|
||||
|
@ -25,6 +25,8 @@ import {
|
||||
import { useCopyToClipboard } from '../../../../hooks/useCopyToClipboard';
|
||||
import UrlIcon from '../../../ui/url-icon/url-icon';
|
||||
import { getAddressBookEntry } from '../../../../selectors';
|
||||
import { ERC1155, ERC721 } from '../../../../../shared/constants/transaction';
|
||||
import NftCollectionImage from '../../../ui/nft-collection-image/nft-collection-image';
|
||||
|
||||
export default function ContractDetailsModal({
|
||||
onClose,
|
||||
@ -35,6 +37,9 @@ export default function ContractDetailsModal({
|
||||
rpcPrefs,
|
||||
origin,
|
||||
siteImage,
|
||||
tokenId,
|
||||
assetName,
|
||||
assetStandard,
|
||||
}) {
|
||||
const t = useI18nContext();
|
||||
const [copiedTokenAddress, handleCopyTokenAddress] = useCopyToClipboard();
|
||||
@ -43,6 +48,12 @@ export default function ContractDetailsModal({
|
||||
const addressBookEntry = useSelector((state) => ({
|
||||
data: getAddressBookEntry(state, toAddress),
|
||||
}));
|
||||
const nft =
|
||||
assetStandard === ERC721 ||
|
||||
assetStandard === ERC1155 ||
|
||||
// if we don't have an asset standard but we do have either both an assetname and a tokenID or both a tokenName and tokenId we assume its an NFT
|
||||
(assetName && tokenId) ||
|
||||
(tokenName && tokenId);
|
||||
|
||||
return (
|
||||
<Popover className="contract-details-modal">
|
||||
@ -75,7 +86,7 @@ export default function ContractDetailsModal({
|
||||
marginTop={4}
|
||||
marginBottom={2}
|
||||
>
|
||||
{t('contractToken')}
|
||||
{nft ? t('contractNFT') : t('contractToken')}
|
||||
</Typography>
|
||||
<Box
|
||||
display={DISPLAY.FLEX}
|
||||
@ -84,11 +95,20 @@ export default function ContractDetailsModal({
|
||||
borderColor={COLORS.BORDER_DEFAULT}
|
||||
className="contract-details-modal__content__contract"
|
||||
>
|
||||
<Identicon
|
||||
className="contract-details-modal__content__contract__identicon"
|
||||
address={tokenAddress}
|
||||
diameter={24}
|
||||
/>
|
||||
{nft ? (
|
||||
<Box margin={4}>
|
||||
<NftCollectionImage
|
||||
assetName={assetName}
|
||||
tokenAddress={tokenAddress}
|
||||
/>
|
||||
</Box>
|
||||
) : (
|
||||
<Identicon
|
||||
className="contract-details-modal__content__contract__identicon"
|
||||
address={tokenAddress}
|
||||
diameter={24}
|
||||
/>
|
||||
)}
|
||||
<Box data-testid="recipient">
|
||||
<Typography
|
||||
fontWeight={FONT_WEIGHT.BOLD}
|
||||
@ -102,6 +122,8 @@ export default function ContractDetailsModal({
|
||||
variant={TYPOGRAPHY.H6}
|
||||
display={DISPLAY.FLEX}
|
||||
color={COLORS.TEXT_ALTERNATIVE}
|
||||
marginTop={0}
|
||||
marginBottom={4}
|
||||
>
|
||||
{ellipsify(tokenAddress)}
|
||||
</Typography>
|
||||
@ -166,7 +188,9 @@ export default function ContractDetailsModal({
|
||||
marginTop={4}
|
||||
marginBottom={2}
|
||||
>
|
||||
{t('contractRequestingSpendingCap')}
|
||||
{nft
|
||||
? t('contractRequestingAccess')
|
||||
: t('contractRequestingSpendingCap')}
|
||||
</Typography>
|
||||
<Box
|
||||
display={DISPLAY.FLEX}
|
||||
@ -175,22 +199,30 @@ export default function ContractDetailsModal({
|
||||
borderColor={COLORS.BORDER_DEFAULT}
|
||||
className="contract-details-modal__content__contract"
|
||||
>
|
||||
<UrlIcon
|
||||
className={classnames({
|
||||
'contract-details-modal__content__contract__identicon-for-unknown-contact':
|
||||
addressBookEntry?.data?.name === undefined,
|
||||
'contract-details-modal__content__contract__identicon':
|
||||
addressBookEntry?.data?.name !== undefined,
|
||||
})}
|
||||
fallbackClassName={classnames({
|
||||
'contract-details-modal__content__contract__identicon-for-unknown-contact':
|
||||
addressBookEntry?.data?.name === undefined,
|
||||
'contract-details-modal__content__contract__identicon':
|
||||
addressBookEntry?.data?.name !== undefined,
|
||||
})}
|
||||
name={origin}
|
||||
url={siteImage}
|
||||
/>
|
||||
{nft ? (
|
||||
<Identicon
|
||||
className="contract-details-modal__content__contract__identicon"
|
||||
diameter={24}
|
||||
address={toAddress}
|
||||
/>
|
||||
) : (
|
||||
<UrlIcon
|
||||
className={classnames({
|
||||
'contract-details-modal__content__contract__identicon-for-unknown-contact':
|
||||
addressBookEntry?.data?.name === undefined,
|
||||
'contract-details-modal__content__contract__identicon':
|
||||
addressBookEntry?.data?.name !== undefined,
|
||||
})}
|
||||
fallbackClassName={classnames({
|
||||
'contract-details-modal__content__contract__identicon-for-unknown-contact':
|
||||
addressBookEntry?.data?.name === undefined,
|
||||
'contract-details-modal__content__contract__identicon':
|
||||
addressBookEntry?.data?.name !== undefined,
|
||||
})}
|
||||
name={origin}
|
||||
url={siteImage}
|
||||
/>
|
||||
)}
|
||||
<Box data-testid="recipient">
|
||||
<Typography
|
||||
fontWeight={FONT_WEIGHT.BOLD}
|
||||
@ -204,6 +236,8 @@ export default function ContractDetailsModal({
|
||||
variant={TYPOGRAPHY.H6}
|
||||
display={DISPLAY.FLEX}
|
||||
color={COLORS.TEXT_ALTERNATIVE}
|
||||
marginTop={0}
|
||||
marginBottom={4}
|
||||
>
|
||||
{ellipsify(toAddress)}
|
||||
</Typography>
|
||||
@ -310,4 +344,16 @@ ContractDetailsModal.propTypes = {
|
||||
* Dapp image
|
||||
*/
|
||||
siteImage: PropTypes.string,
|
||||
/**
|
||||
* The token id of the collectible
|
||||
*/
|
||||
tokenId: PropTypes.string,
|
||||
/**
|
||||
* Token Standard
|
||||
*/
|
||||
assetStandard: PropTypes.string,
|
||||
/**
|
||||
* The name of the collection
|
||||
*/
|
||||
assetName: PropTypes.string,
|
||||
};
|
||||
|
@ -1,12 +1,15 @@
|
||||
.contract-details-modal {
|
||||
width: 360px !important;
|
||||
width: 100% !important;
|
||||
max-width: 408px;
|
||||
|
||||
&__content {
|
||||
border-bottom: 1px solid var(--color-border-muted);
|
||||
|
||||
&__contract {
|
||||
&__identicon {
|
||||
margin: 16px 16px 38px 16px;
|
||||
margin: 16px;
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
&__identicon-for-unknown-contact {
|
||||
|
1
ui/components/ui/nft-collection-image/index.js
Normal file
1
ui/components/ui/nft-collection-image/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './nft-collection-image';
|
7
ui/components/ui/nft-collection-image/index.scss
Normal file
7
ui/components/ui/nft-collection-image/index.scss
Normal file
@ -0,0 +1,7 @@
|
||||
.collection-image-alt {
|
||||
border-radius: 50%;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 2px;
|
||||
background: var(--color-overlay-alternative);
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import Box from '../box';
|
||||
import { COLORS, TEXT_ALIGN } from '../../../helpers/constants/design-system';
|
||||
import Identicon from '../identicon';
|
||||
import { getTokenList } from '../../../selectors';
|
||||
import { useCollectiblesCollections } from '../../../hooks/useCollectiblesCollections';
|
||||
|
||||
export default function NftCollectionImage({ assetName, tokenAddress }) {
|
||||
const { collections } = useCollectiblesCollections();
|
||||
const tokenList = useSelector(getTokenList);
|
||||
const nftTokenListImage = tokenList[tokenAddress.toLowerCase()]?.iconUrl;
|
||||
|
||||
const renderCollectionImageOrName = () => {
|
||||
const collection = Object.values(collections).find(
|
||||
({ collectionName }) => collectionName === assetName,
|
||||
);
|
||||
|
||||
if (collection?.collectionImage || nftTokenListImage) {
|
||||
return (
|
||||
<Identicon
|
||||
diameter={24}
|
||||
image={collection?.collectionImage || nftTokenListImage}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Box
|
||||
color={COLORS.OVERLAY_INVERSE}
|
||||
textAlign={TEXT_ALIGN.CENTER}
|
||||
className="collection-image-alt"
|
||||
>
|
||||
{assetName?.[0]?.toUpperCase() ?? null}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
return <Box>{renderCollectionImageOrName()}</Box>;
|
||||
}
|
||||
|
||||
NftCollectionImage.propTypes = {
|
||||
assetName: PropTypes.string,
|
||||
tokenAddress: PropTypes.string,
|
||||
};
|
@ -63,3 +63,5 @@
|
||||
@import 'deprecated-test-networks/index.scss';
|
||||
@import 'contract-token-values/index.scss';
|
||||
@import 'nft-info/index.scss';
|
||||
@import 'nft-collection-image/index';
|
||||
|
||||
|
@ -32,6 +32,7 @@ import {
|
||||
ERC721,
|
||||
} from '../../../../shared/constants/transaction';
|
||||
import { CHAIN_IDS, TEST_CHAINS } from '../../../../shared/constants/network';
|
||||
import ContractDetailsModal from '../../../components/app/modals/contract-details-modal/contract-details-modal';
|
||||
|
||||
export default class ConfirmApproveContent extends Component {
|
||||
static contextTypes = {
|
||||
@ -82,6 +83,7 @@ export default class ConfirmApproveContent extends Component {
|
||||
state = {
|
||||
showFullTxDetails: false,
|
||||
copied: false,
|
||||
setshowContractDetails: false,
|
||||
};
|
||||
|
||||
renderApproveContentCard({
|
||||
@ -588,8 +590,11 @@ export default class ConfirmApproveContent extends Component {
|
||||
isContract,
|
||||
assetStandard,
|
||||
userAddress,
|
||||
tokenId,
|
||||
tokenAddress,
|
||||
assetName,
|
||||
} = this.props;
|
||||
const { showFullTxDetails } = this.state;
|
||||
const { showFullTxDetails, setshowContractDetails } = this.state;
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -632,6 +637,33 @@ export default class ConfirmApproveContent extends Component {
|
||||
<div className="confirm-approve-content__description">
|
||||
{this.renderDescription()}
|
||||
</div>
|
||||
{(assetStandard === ERC721 ||
|
||||
assetStandard === ERC1155 ||
|
||||
(assetName && tokenId) ||
|
||||
(tokenSymbol && tokenId)) && (
|
||||
<Box marginBottom={4} marginTop={2}>
|
||||
<Button
|
||||
type="link"
|
||||
className="confirm-approve-content__verify-contract-details"
|
||||
onClick={() => this.setState({ setshowContractDetails: true })}
|
||||
>
|
||||
{t('verifyContractDetails')}
|
||||
</Button>
|
||||
{setshowContractDetails && (
|
||||
<ContractDetailsModal
|
||||
onClose={() => this.setState({ setshowContractDetails: false })}
|
||||
tokenName={tokenSymbol}
|
||||
tokenAddress={tokenAddress}
|
||||
toAddress={toAddress}
|
||||
chainId={chainId}
|
||||
rpcPrefs={rpcPrefs}
|
||||
tokenId={tokenId}
|
||||
assetName={assetName}
|
||||
assetStandard={assetStandard}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
<Box className="confirm-approve-content__address-display-content">
|
||||
<Box display={DISPLAY.FLEX}>
|
||||
<Identicon
|
||||
|
@ -102,7 +102,6 @@
|
||||
@include H6;
|
||||
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
color: var(--color-text-alternative);
|
||||
text-align: center;
|
||||
padding-left: 24px;
|
||||
@ -337,6 +336,13 @@
|
||||
color: var(--color-primary-default);
|
||||
}
|
||||
|
||||
&__verify-contract-details {
|
||||
@include H6;
|
||||
|
||||
color: var(--color-primary-default);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&__info-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
Loading…
Reference in New Issue
Block a user