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

Hide assets from views #1797

Open
wants to merge 15 commits into
base: release/5.28.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
39 changes: 39 additions & 0 deletions @shared/api/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ import {
IndexerSettings,
SettingsState,
ExperimentalFeatures,
AssetKey,
AssetVisibility,
} from "./types";
import {
MAINNET_NETWORK_DETAILS,
Expand Down Expand Up @@ -1208,6 +1210,7 @@ export const saveSettings = async ({
isNonSSLEnabled: false,
isHideDustEnabled: true,
error: "",
hiddenAssets: {},
};

try {
Expand Down Expand Up @@ -1529,3 +1532,39 @@ export const simulateTransaction = async (args: {
response,
};
};

export const getHiddenAssets = async () => {
let response = {
error: "",
hiddenAssets: {} as Record<AssetKey, AssetVisibility>,
};

response = await sendMessageToBackground({
type: SERVICE_TYPES.GET_HIDDEN_ASSETS,
});

return { hiddenAssets: response.hiddenAssets, error: response.error };
};

export const changeAssetVisibility = async ({
assetIssuer,
assetVisibility,
}: {
assetIssuer: AssetKey;
assetVisibility: AssetVisibility;
}) => {
let response = {
error: "",
hiddenAssets: {} as Record<AssetKey, AssetVisibility>,
};

response = await sendMessageToBackground({
type: SERVICE_TYPES.CHANGE_ASSET_VISIBILITY,
assetVisibility: {
issuer: assetIssuer,
Copy link
Contributor

Choose a reason for hiding this comment

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

We'll run into an issue here when a G address is the issuer for multiple assets.

Here's an example of an issuer on Mainnet who issues multiple assets under one address: GBX23RCWKV7DA23J2MA2OFMTRV3XZHHKOTHBQF6AKOEP7AGQUIZZXLMG

I think you might just want to use {assetCode}:{assetIssuer} as your key here

Choose a reason for hiding this comment

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

@

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@piyalbasu very good point thank you, will update to use the composite key.
Can an issuer have two assets that use the same ticker?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done in 0512f6c

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, that's a good question about multiple assets using the same ticket. Off the top of my head, I'm not 100% sure. We may need to test it out and see if the network lets us do it

visibility: assetVisibility,
},
});

return { hiddenAssets: response.hiddenAssets, error: response.error };
};
9 changes: 9 additions & 0 deletions @shared/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export interface UserInfo {

export type MigratableAccount = Account & { keyIdIndex: number };

export type AssetKey = string; // {assetCode}:{issuer/contract ID} issuer pub key for classic, contract ID for tokens
export type AssetVisibility = "visible" | "hidden";

export interface Response {
error: string;
apiError: FreighterApiError;
Expand Down Expand Up @@ -93,6 +96,11 @@ export interface Response {
recommendedFee: string;
isNonSSLEnabled: boolean;
isHideDustEnabled: boolean;
assetVisibility: {
issuer: AssetKey;
visibility: AssetVisibility;
};
hiddenAssets: Record<AssetKey, AssetVisibility>;
}

export interface MemoRequiredAccount {
Expand Down Expand Up @@ -182,6 +190,7 @@ export type Settings = {
networkDetails: NetworkDetails;
networksList: NetworkDetails[];
error: string;
hiddenAssets: Record<AssetKey, AssetVisibility>;
} & Preferences;

export interface AssetIcons {
Expand Down
2 changes: 2 additions & 0 deletions @shared/constants/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export enum SERVICE_TYPES {
MIGRATE_ACCOUNTS = "MIGRATE_ACCOUNTS",
ADD_ASSETS_LIST = "ADD_ASSETS_LIST",
MODIFY_ASSETS_LIST = "MODIFY_ASSETS_LIST",
CHANGE_ASSET_VISIBILITY = "CHANGE_ASSET_VISIBILITY",
GET_HIDDEN_ASSETS = "GET_HIDDEN_ASSETS",
}

export enum EXTERNAL_SERVICE_TYPES {
Expand Down
4 changes: 2 additions & 2 deletions extension/e2e-tests/addAsset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test("Adding unverified Soroban token", async ({ page, extensionId }) => {

await page.getByTestId("account-options-dropdown").click();
await page.getByText("Manage assets").click({ force: true });
await expect(page.getByText("Your assets")).toBeVisible();
await expect(page.getByText("Manage assets")).toBeVisible();
await expectPageToHaveScreenshot({
page,
screenshot: "manage-assets-page.png",
Expand Down Expand Up @@ -40,7 +40,7 @@ test("Adding Soroban verified token", async ({ page, extensionId }) => {
await page.getByTestId("account-options-dropdown").click();
await page.getByText("Manage Assets").click({ force: true });

await expect(page.getByText("Your assets")).toBeVisible();
await expect(page.getByText("Manage assets")).toBeVisible();
await page.getByText("Add an asset").click({ force: true });
await page.getByText("Add manually").click({ force: true });
await page.getByTestId("search-token-input").fill(USDC_TOKEN_ADDRESS);
Expand Down
2 changes: 1 addition & 1 deletion extension/e2e-tests/loadAccount.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ test("Switches account without password prompt", async ({
await page.getByTestId("account-options-dropdown").click();
await page.getByText("Manage Assets").click({ force: true });

await expect(page.getByText("Your assets")).toBeVisible();
await expect(page.getByText("Manage assets")).toBeVisible();
});
2 changes: 1 addition & 1 deletion extension/e2e-tests/sendPayment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ test("Send token payment to C address", async ({ page, extensionId }) => {
// add E2E token
await page.getByTestId("account-options-dropdown").click();
await page.getByText("Manage Assets").click({ force: true });
await expect(page.getByText("Your assets")).toBeVisible();
await expect(page.getByText("Manage assets")).toBeVisible();
await page.getByText("Add an asset").click({ force: true });
await page.getByText("Add manually").click({ force: true });
await page.getByTestId("search-token-input").fill(TEST_TOKEN_ADDRESS);
Expand Down
20 changes: 20 additions & 0 deletions extension/src/background/messageListener/popupMessageListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
IS_HASH_SIGNING_ENABLED_ID,
IS_NON_SSL_ENABLED_ID,
IS_HIDE_DUST_ENABLED_ID,
HIDDEN_ASSETS,
} from "constants/localStorageTypes";
import {
FUTURENET_NETWORK_DETAILS,
Expand Down Expand Up @@ -1316,6 +1317,7 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {
const assetsLists = await getAssetsLists();
const isNonSSLEnabled = await getIsNonSSLEnabled();
const isHideDustEnabled = await getIsHideDustEnabled();
const { hiddenAssets } = await getHiddenAssets();

return {
allowList: await getAllowList(),
Expand All @@ -1331,6 +1333,7 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {
assetsLists,
isNonSSLEnabled,
isHideDustEnabled,
hiddenAssets,
};
};

Expand Down Expand Up @@ -1766,6 +1769,21 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {
return { assetsLists: await getAssetsLists() };
};

const changeAssetVisibility = async () => {
const { assetVisibility } = request;

const { hiddenAssets } = await getHiddenAssets();
hiddenAssets[assetVisibility.issuer] = assetVisibility.visibility;

await localStore.setItem(HIDDEN_ASSETS, hiddenAssets);
return { hiddenAssets };
};

const getHiddenAssets = async () => {
const hiddenAssets = (await localStore.getItem(HIDDEN_ASSETS)) || {};
return { hiddenAssets };
};

const messageResponder: MessageResponder = {
[SERVICE_TYPES.CREATE_ACCOUNT]: createAccount,
[SERVICE_TYPES.FUND_ACCOUNT]: fundAccount,
Expand Down Expand Up @@ -1818,6 +1836,8 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => {
[SERVICE_TYPES.MIGRATE_ACCOUNTS]: migrateAccounts,
[SERVICE_TYPES.ADD_ASSETS_LIST]: addAssetsList,
[SERVICE_TYPES.MODIFY_ASSETS_LIST]: modifyAssetsList,
[SERVICE_TYPES.CHANGE_ASSET_VISIBILITY]: changeAssetVisibility,
[SERVICE_TYPES.GET_HIDDEN_ASSETS]: getHiddenAssets,
};

return messageResponder[request.type]();
Expand Down
1 change: 1 addition & 0 deletions extension/src/constants/localStorageTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ export const IS_HASH_SIGNING_ENABLED_ID = "isHashSigningEnabled";
export const IS_NON_SSL_ENABLED_ID = "isNonSSLEnabled";
export const IS_BLOCKAID_ANNOUNCED_ID = "isBlockaidAnnounced";
export const IS_HIDE_DUST_ENABLED_ID = "isHideDustEnabled";
export const HIDDEN_ASSETS = "hiddenAssets";
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React, { useEffect, useRef } from "react";
import { useHistory } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { useTranslation } from "react-i18next";
import { Loader } from "@stellar/design-system";

import { View } from "popup/basics/layout/View";
import { SubviewHeader } from "popup/components/SubviewHeader";
import {
getAccountBalances,
resetSubmission,
} from "popup/ducks/transactionSubmission";
import {
settingsNetworkDetailsSelector,
settingsSorobanSupportedSelector,
} from "popup/ducks/settings";
import { publicKeySelector } from "popup/ducks/accountServices";
import { useFetchDomains } from "popup/helpers/useFetchDomains";
import { ToggleAssetRows } from "../ToggleAssetRows";

import "./styles.scss";

export const AssetVisibility = () => {
const { t } = useTranslation();
const history = useHistory();
const isSorobanSuported = useSelector(settingsSorobanSupportedSelector);
const networkDetails = useSelector(settingsNetworkDetailsSelector);
const dispatch = useDispatch();
const publicKey = useSelector(publicKeySelector);

const ManageAssetRowsWrapperRef = useRef<HTMLDivElement>(null);

const { assets, isManagingAssets } = useFetchDomains();

useEffect(() => {
dispatch(
getAccountBalances({
publicKey,
networkDetails,
showHidden: true,
}),
);
return () => {
dispatch(resetSubmission());
};
}, [publicKey, dispatch, networkDetails]);

const goBack = () => {
dispatch(resetSubmission());
history.goBack();
};

return (
<View>
<SubviewHeader customBackAction={goBack} title={t("Toggle Assets")} />
<View.Content hasNoTopPadding>
{assets.isLoading ? (
<div className="ToggleAsset__loader">
<Loader size="2rem" />
</div>
) : (
<div className="ToggleAsset__wrapper">
<div
className={`ToggleAsset__assets${
isManagingAssets && isSorobanSuported ? "--short" : ""
}`}
ref={ManageAssetRowsWrapperRef}
>
<ToggleAssetRows assetRows={assets.assetRows} />
</div>
</div>
)}
</View.Content>
</View>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
.ToggleAsset {
&__close-btn {
color: var(--sds-clr-gray-10);
}

&__hide-btn {
background-color: transparent;
border: none;
padding: 0;
align-items: center;
cursor: pointer;
display: flex;
width: var(--back--button-dimension);
height: var(--back--button-dimension);
color: var(--sds-clr-gray-10);
}

&__loader {
height: 100%;
width: 100%;
z-index: calc(var(--back--button-z-index) + 1);
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
top: 0;
left: 0;
}

&__wrapper {
display: flex;
flex-direction: column;
height: 100%;
}

&__assets {
flex-grow: 1;
}

&__button {
a {
color: var(--sds-clr-gray-12);
}

button {
text-wrap: nowrap;
}
}
}
Loading
Loading