Skip to content

Commit

Permalink
Feature/check multiple tokenlist (#1221)
Browse files Browse the repository at this point in the history
* first pass at adding multiple asset lists

* add verification badge

* add asset notifcation tooltip

* Added translations

* rm consoles

* update yarn

* reset debounce param

* use getTokenDetails

* fix tests
  • Loading branch information
piyalbasu authored Mar 30, 2024
1 parent d00cd85 commit 8df22b1
Show file tree
Hide file tree
Showing 15 changed files with 373 additions and 283 deletions.
1 change: 0 additions & 1 deletion extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
"@shared/api": "1.0.0",
"@shared/constants": "1.0.0",
"@shared/helpers": "1.0.0",
"@stellar-asset-lists/sdk": "^1.0.0",
"@stellar/design-system": "^1.1.2",
"@stellar/wallet-sdk": "v0.11.0-beta.1",
"@testing-library/react": "^14.2.1",
Expand Down
10 changes: 10 additions & 0 deletions extension/src/popup/assets/icon-new-asset.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions extension/src/popup/assets/icon-unverified.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions extension/src/popup/components/AssetNotification/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Tooltip, Icon } from "@stellar/design-system";

import "./styles.scss";

export const AssetNotifcation = ({ isVerified }: { isVerified: boolean }) => {
const { t } = useTranslation();

return (
<div className="AssetNotification" data-testid="asset-notification">
{isVerified ? t("On your lists") : t("Not on your lists")}
<Tooltip
placement="right"
triggerEl={
<button className="AssetNotification__button">
<Icon.Info className="AssetNotification__info" />
</button>
}
>
{t(
"Freighter uses asset lists to check assets you interact with. You can define your own assets lists in Settings.",
)}
</Tooltip>
</div>
);
};
24 changes: 24 additions & 0 deletions extension/src/popup/components/AssetNotification/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.AssetNotification {
align-items: center;
color: var(--color-gray-70);
display: flex;
font-size: 0.875rem;
font-weight: var(--font-weight-medium);
gap: 0.25rem;
line-height: 1.25rem;
margin-bottom: 1rem;

&__button {
border: none;
background: none;
display: flex;
text-decoration: none;
cursor: pointer;
padding: 0;
}

&__info {
height: 0.875rem;
width: 0.875rem;
}
}
152 changes: 79 additions & 73 deletions extension/src/popup/components/WarningMessages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import React, { useState, useRef, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { createPortal } from "react-dom";
import {
Button,
Icon,
Loader,
Link,
Notification,
} from "@stellar/design-system";
import { Button, Icon, Loader, Notification } from "@stellar/design-system";
import { useTranslation } from "react-i18next";
import { POPUP_HEIGHT } from "constants/dimensions";
import {
Expand All @@ -19,6 +13,7 @@ import {
Networks,
xdr,
} from "stellar-sdk";
import { captureException } from "@sentry/browser";

import { ActionStatus } from "@shared/api/types";
import { getTokenDetails } from "@shared/api/internal";
Expand Down Expand Up @@ -57,8 +52,12 @@ import { emitMetric } from "helpers/metrics";
import IconShieldCross from "popup/assets/icon-shield-cross.svg";
import IconInvalid from "popup/assets/icon-invalid.svg";
import IconWarning from "popup/assets/icon-warning.svg";
import { searchToken } from "popup/helpers/searchAsset";
import { captureException } from "@sentry/browser";
import IconUnverified from "popup/assets/icon-unverified.svg";
import IconNewAsset from "popup/assets/icon-new-asset.svg";
import {
getVerifiedTokens,
VerifiedTokenRecord,
} from "popup/helpers/searchAsset";
import { CopyValue } from "../CopyValue";

import "./styles.scss";
Expand Down Expand Up @@ -689,16 +688,20 @@ export const NewAssetWarning = ({
);
};

export const UnverifiedTokenWarning = ({
export const TokenWarning = ({
domain,
code,
issuer,
onClose,
isVerifiedToken,
verifiedLists = [],
}: {
domain: string;
code: string;
issuer: string;
onClose: () => void;
isVerifiedToken: boolean;
verifiedLists?: string[];
}) => {
const { t } = useTranslation();
const dispatch: AppDispatch = useDispatch();
Expand Down Expand Up @@ -746,70 +749,78 @@ export const UnverifiedTokenWarning = ({
};

return (
<div className="UnverifiedTokenWarning">
<div className="TokenWarning">
<View.Content>
<div className="UnverifiedTokenWarning__wrapper" ref={warningRef}>
<div className="UnverifiedTokenWarning__heading">
<div className="UnverifiedTokenWarning__icon">
<div className="TokenWarning__wrapper" ref={warningRef}>
<div className="TokenWarning__heading">
<div className="TokenWarning__icon">
<SorobanTokenIcon noMargin />
</div>
<div className="UnverifiedTokenWarning__code">{code}</div>
<div className="UnverifiedTokenWarning__domain">{domain}</div>
<div className="UnverifiedTokenWarning__description">
<div className="UnverifiedTokenWarning__description__icon">
<div className="TokenWarning__code">{code}</div>
<div className="TokenWarning__domain">{domain}</div>
<div className="TokenWarning__description">
<div className="TokenWarning__description__icon">
<Icon.VerifiedUser />
</div>
<div className="UnverifiedTokenWarning__description__text">
<div className="TokenWarning__description__text">
{t("Add Asset Trustline")}
</div>
</div>
</div>
{isVerifiedToken ? (
<Notification
title={`${t(
"This asset is part of the asset lists",
)} "${verifiedLists.join(", ")}."`}
variant="primary"
>
{t(
"Freighter uses asset lists to check assets you interact with. You can define your own assets lists in Settings.",
)}
</Notification>
) : (
<Notification
title={t(
"This asset is not part of an asset list. Please, double-check the asset you're interacting with and proceed with care. Freighter uses asset lists to check assets you interact with. You can define your own assets lists in Settings.",
)}
variant="warning"
/>
)}

<div className="TokenWarning__flags">
<div className="TokenWarning__flags__info">{t("Asset Info")}</div>

<Notification
title={t(
"Before you add this asset, please double-check its information and characteristics. This can help you identify fraudulent assets.",
{isVerifiedToken ? null : (
<div className="TokenWarning__flag">
<div className="TokenWarning__flag__icon">
<img src={IconUnverified} alt="unverified icon" />
</div>
<div className="TokenWarning_flag__content">
<div className="TokenWarning__flag__header TokenWarning__flag__icon--unverified">
{t("Unverified asset")}
</div>
<div className="TokenWarning__flag__content">
{t("Proceed with caution")}
</div>
</div>
</div>
)}
variant="warning"
/>
<div className="UnverifiedTokenWarning__flags">
<div className="UnverifiedTokenWarning__flags__info">
{t("Asset Info")}
</div>
<div className="UnverifiedTokenWarning__flag">
<div className="UnverifiedTokenWarning__flag__icon">
<Icon.Info />
<div className="TokenWarning__flag">
<div className="TokenWarning__flag__icon">
<img src={IconNewAsset} alt="new asset icon" />
</div>
<div className="UnverifiedTokenWarning__flag__content">
<div className="UnverifiedTokenWarning__flag__header UnverifiedTokenWarning__flags__icon--unverified">
{t(
"The asset is not part of Stellar Expert's top 50 assets list",
)}
<div className="TokenWarning_flag__content">
<div className="TokenWarning__flag__header TokenWarning__flag__icon">
{t("New asset")}
</div>
<div className="UnverifiedTokenWarning__flag__description">
{t("This asset is not part of")}{" "}
<Link
isUnderline
variant="secondary"
href="https://api.stellar.expert/explorer/testnet/asset-list/top50"
target="_blank"
rel="noreferrer"
>
Stellar Expert's top 50 assets list
</Link>
<br />
<Link
isUnderline
variant="secondary"
href="https://www.freighter.app/faq"
>
{t("Learn more")}
</Link>
<div className="TokenWarning__flag__content">
{t("This is a relatively new asset")}
</div>
</div>
</div>
</div>

<div className="UnverifiedTokenWarning__bottom-content">
<div className="TokenWarning__bottom-content">
<div className="ScamAssetWarning__btns">
<Button
size="md"
Expand Down Expand Up @@ -904,29 +915,24 @@ export const UnverifiedTokenTransferWarning = ({
details: { contractId: string }[];
}) => {
const { t } = useTranslation();
const networkDetails = useSelector(settingsNetworkDetailsSelector);
const { networkDetails, assetsLists } = useSelector(settingsSelector);
const [isUnverifiedToken, setIsUnverifiedToken] = useState(false);

useEffect(() => {
if (!isMainnet(networkDetails) && !isTestnet(networkDetails)) {
return;
}
const fetchVerifiedTokens = async () => {
const verifiedTokenRes = await searchToken({
networkDetails,
onError: (e) => console.error(e),
});
const verifiedTokens = [] as string[];
let verifiedTokens = [] as VerifiedTokenRecord[];

// eslint-disable-next-line
for (let i = 0; i < verifiedTokenRes.length; i += 1) {
// eslint-disable-next-line
for (let j = 0; j < details.length; j += 1) {
if (details[j].contractId === verifiedTokenRes[i].contract) {
verifiedTokens.push(details[j].contractId);
return;
}
}
for (let j = 0; j < details.length; j += 1) {
const c = details[j].contractId;
verifiedTokens = await getVerifiedTokens({
contractId: c,
networkDetails,
assetsLists,
});
}

if (!verifiedTokens.length) {
Expand All @@ -935,17 +941,17 @@ export const UnverifiedTokenTransferWarning = ({
};

fetchVerifiedTokens();
}, [networkDetails, details]);
}, [networkDetails, details, assetsLists]);

return isUnverifiedToken ? (
<WarningMessage
header="This asset is not on the asset list"
header="This asset is not on an asset list"
variant={WarningMessageVariant.default}
>
<div className="TokenTransferWarning">
<p>
{t(
`This asset is not part of the asset list by stellar.expert (${networkDetails.network})`,
`This asset is not part of any of your enabled asset lists (${networkDetails.network})`,
)}
</p>
</div>
Expand Down
13 changes: 9 additions & 4 deletions extension/src/popup/components/WarningMessages/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@
}
}

.UnverifiedTokenWarning {
.TokenWarning {
z-index: var(--z-index--scam-warning);
display: flex;
position: fixed;
Expand Down Expand Up @@ -340,7 +340,7 @@

&__flag {
display: flex;
margin-bottom: 1.5rem;
margin-bottom: 0.375rem;
column-gap: 0.5rem;
&__header {
color: var(--color-white);
Expand All @@ -352,8 +352,13 @@
font-size: 0.75rem;
line-height: 1.25rem;
}
&__icon {
color: var(--color-purple-50);
&__icon--unverified {
color: var(--color-yellow-50);
}
&__content {
color: var(--color-gray-70);
font-size: 0.875rem;
line-height: 1.125rem;
}
}

Expand Down
Loading

0 comments on commit 8df22b1

Please sign in to comment.