Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/check multiple tokenlist #1221

Merged
merged 11 commits into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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">
{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")}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This "relatively new asset" is hardcoded for now (as all the assets are "relatively new" 😄 ). I'm looking into how we can actually figure out if an asset is now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could index for new token deployments in the future but yeah not sure what else we could do right now.

</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
Loading