diff --git a/frontend/src/lib/components/common/LinkIcon.svelte b/frontend/src/lib/components/common/LinkIcon.svelte index cebe0267159..caf2293e603 100644 --- a/frontend/src/lib/components/common/LinkIcon.svelte +++ b/frontend/src/lib/components/common/LinkIcon.svelte @@ -1,5 +1,5 @@ diff --git a/frontend/src/lib/components/ui/PrincipalInput.svelte b/frontend/src/lib/components/ui/PrincipalInput.svelte index f1bcfae629c..9c224c1ddd6 100644 --- a/frontend/src/lib/components/ui/PrincipalInput.svelte +++ b/frontend/src/lib/components/ui/PrincipalInput.svelte @@ -8,6 +8,7 @@ export let name: string; export let principal: Principal | undefined = undefined; export let required: boolean | undefined = undefined; + export let testId: string | undefined = undefined; let address = principal?.toText() ?? ""; $: principal = getPrincipalFromString(address); @@ -24,6 +25,7 @@ inputType="text" {placeholderLabelKey} {name} + {testId} bind:value={address} errorMessage={showError ? $i18n.error.principal_not_valid : undefined} on:blur={showErrorIfAny} diff --git a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte index b537120234d..fef0afd2815 100644 --- a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte +++ b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte @@ -77,7 +77,10 @@ }; const onUserConfirm = async () => { - if (isNullish(ledgerCanisterId) || isNullish($importedTokensStore.importedTokens)) { + if ( + isNullish(ledgerCanisterId) || + isNullish($importedTokensStore.importedTokens) + ) { return; } From 460bd3e5e7c988cc52b451b3011c239b65c4e513 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 31 Jul 2024 11:16:23 +0200 Subject: [PATCH 046/166] feat: propagate more props from PrincipalInput --- frontend/src/lib/components/ui/PrincipalInput.svelte | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/lib/components/ui/PrincipalInput.svelte b/frontend/src/lib/components/ui/PrincipalInput.svelte index baedf068c4b..9c224c1ddd6 100644 --- a/frontend/src/lib/components/ui/PrincipalInput.svelte +++ b/frontend/src/lib/components/ui/PrincipalInput.svelte @@ -7,6 +7,8 @@ export let placeholderLabelKey: string; export let name: string; export let principal: Principal | undefined = undefined; + export let required: boolean | undefined = undefined; + export let testId: string | undefined = undefined; let address = principal?.toText() ?? ""; $: principal = getPrincipalFromString(address); @@ -23,10 +25,12 @@ inputType="text" {placeholderLabelKey} {name} + {testId} bind:value={address} errorMessage={showError ? $i18n.error.principal_not_valid : undefined} on:blur={showErrorIfAny} showInfo={$$slots.label !== undefined} + {required} > From 09ccd99d2d2adccb341f45893a910d636b3bd5b7 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 31 Jul 2024 11:16:44 +0200 Subject: [PATCH 047/166] New component ImportTokenForm --- .../accounts/ImportTokenForm.svelte | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 frontend/src/lib/components/accounts/ImportTokenForm.svelte diff --git a/frontend/src/lib/components/accounts/ImportTokenForm.svelte b/frontend/src/lib/components/accounts/ImportTokenForm.svelte new file mode 100644 index 00000000000..764507daed0 --- /dev/null +++ b/frontend/src/lib/components/accounts/ImportTokenForm.svelte @@ -0,0 +1,72 @@ + + + + {$i18n.import_token.description} + + dispatch("nnsSubmit")}> + + {$i18n.import_token.ledger_label} + + + + + + + + + + + + + + dispatch("nnsClose")} + > + {$i18n.core.cancel} + + + + {$i18n.core.next} + + + + + + From f793680fd5808f47ad27e9f1126ca813473ea4f4 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 31 Jul 2024 11:23:03 +0200 Subject: [PATCH 048/166] Update labels --- frontend/src/lib/i18n/en.json | 16 +++++++++++++++- frontend/src/lib/types/i18n.d.ts | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index 1915f884607..a0097e61326 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -1036,8 +1036,22 @@ "hide_zero_balances": "Hide zero balances", "hide_zero_balances_toggle_label": "Switch between showing and hiding tokens with a balance of zero", "zero_balance_hidden": "Tokens with 0 balances are hidden.", - "show_all": "Show all", + "show_all": "Show all" + }, + "import_token": { "import_token": "Import Token", + "description": "To import a new token to your NNS dapp wallet, you will need to find, and paste the ledger canister id of the token. If you want to see your transaction history, you need to import the token’s index canister.", + "ledger_label": "Ledger Canister ID", + "index_label_optional": "Index Canister ID (Optional)", + "index_label": "Index Canister ID", + "index_fallback_label": "Transaction history won’t be displayed.", + "placeholder": "00000-00000-00000-00000-000", + "index_canister_description": "Index Canister allows to display a token balance and transaction history. Note: not all tokens have index canisters.", + "warning": "Warning: Be careful what token you import! Anyone can create a token including one with the same name as existing tokens, such as ckBTC", + "verifying": "Veryifying token details...", + "review_token_info": "Review token info", + "import_button": "Import", + "link_to_canister": "https://dashboard.internetcomputer.org/canister/$canisterId", "add_imported_token_success": "New token has been successfully imported!", "remove_imported_token_success": "The token has been successfully removed!" } diff --git a/frontend/src/lib/types/i18n.d.ts b/frontend/src/lib/types/i18n.d.ts index 5908d011372..cc9a0ef02fb 100644 --- a/frontend/src/lib/types/i18n.d.ts +++ b/frontend/src/lib/types/i18n.d.ts @@ -1097,7 +1097,22 @@ interface I18nTokens { hide_zero_balances_toggle_label: string; zero_balance_hidden: string; show_all: string; +} + +interface I18nImport_token { import_token: string; + description: string; + ledger_label: string; + index_label_optional: string; + index_label: string; + index_fallback_label: string; + placeholder: string; + index_canister_description: string; + warning: string; + verifying: string; + review_token_info: string; + import_button: string; + link_to_canister: string; add_imported_token_success: string; remove_imported_token_success: string; } @@ -1386,6 +1401,7 @@ interface I18n { settings: I18nSettings; sync: I18nSync; tokens: I18nTokens; + import_token: I18nImport_token; neuron_state: I18nNeuron_state; topics: I18nTopics; topics_description: I18nTopics_description; From 5e3f2eb3cdc6e40c49fc61a4849f85689908251a Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 31 Jul 2024 11:23:53 +0200 Subject: [PATCH 049/166] New busy store initiator --- frontend/src/lib/stores/busy.store.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/stores/busy.store.ts b/frontend/src/lib/stores/busy.store.ts index 95291a7be3b..954680c21e3 100644 --- a/frontend/src/lib/stores/busy.store.ts +++ b/frontend/src/lib/stores/busy.store.ts @@ -45,7 +45,8 @@ export type BusyStateInitiatorType = | "dev-add-sns-neuron-maturity" | "dev-add-nns-neuron-maturity" | "update-ckbtc-balance" - | "reload-receive-account"; + | "reload-receive-account" + | "import-token-validation"; export interface BusyState { initiator: BusyStateInitiatorType; From 77d3b2084878704bc701a153733ac753266e3882 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 31 Jul 2024 11:24:02 +0200 Subject: [PATCH 050/166] feat: fetchIcrcTokenMetaData service --- .../src/lib/services/icrc-accounts.services.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/services/icrc-accounts.services.ts b/frontend/src/lib/services/icrc-accounts.services.ts index 32fd445e16a..bcb3ae81d0f 100644 --- a/frontend/src/lib/services/icrc-accounts.services.ts +++ b/frontend/src/lib/services/icrc-accounts.services.ts @@ -5,7 +5,10 @@ import { } from "$lib/api/icrc-ledger.api"; import { FORCE_CALL_STRATEGY } from "$lib/constants/mockable.constants"; import { snsTokensByLedgerCanisterIdStore } from "$lib/derived/sns/sns-tokens.derived"; -import { getAuthenticatedIdentity } from "$lib/services/auth.services"; +import { + getAuthenticatedIdentity, + getCurrentIdentity, +} from "$lib/services/auth.services"; import { icrcAccountsStore } from "$lib/stores/icrc-accounts.store"; import { icrcTransactionsStore } from "$lib/stores/icrc-transactions.store"; import { toastsError } from "$lib/stores/toasts.store"; @@ -32,6 +35,19 @@ export const getIcrcAccountIdentity = (_: Account): Promise => { return getAuthenticatedIdentity(); }; +// Returns null if the token is not found +export const fetchIcrcTokenMetaData = async ({ + ledgerCanisterId, +}: { + ledgerCanisterId: Principal; +}): Promise => { + return queryIcrcToken({ + identity: getCurrentIdentity(), + canisterId: ledgerCanisterId, + certified: false, + }).catch(() => null); +}; + export const loadIcrcToken = ({ ledgerCanisterId, certified = true, From 73e8970b243f12a7ead626df3bfab72feaa9eb00 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 31 Jul 2024 11:24:36 +0200 Subject: [PATCH 051/166] New component ImportTokenReview --- .../accounts/ImportTokenReview.svelte | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 frontend/src/lib/components/accounts/ImportTokenReview.svelte diff --git a/frontend/src/lib/components/accounts/ImportTokenReview.svelte b/frontend/src/lib/components/accounts/ImportTokenReview.svelte new file mode 100644 index 00000000000..3b179b3a436 --- /dev/null +++ b/frontend/src/lib/components/accounts/ImportTokenReview.svelte @@ -0,0 +1,108 @@ + + + + + + + {tokenMetaData.name} + + {tokenMetaData.symbol} + + + + + + + + + + + + + + + + dispatch("nnsBack")} + > + {$i18n.core.back} + + + dispatch("nnsConfirm")} + > + {$i18n.import_token.import_button} + + + + + From e988727368c2f44c036c6b6a765efd4bf0918b84 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 31 Jul 2024 11:25:07 +0200 Subject: [PATCH 052/166] New component ImportTokenModal --- .../modals/accounts/ImportTokenModal.svelte | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 frontend/src/lib/modals/accounts/ImportTokenModal.svelte diff --git a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte new file mode 100644 index 00000000000..de3dc051f42 --- /dev/null +++ b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte @@ -0,0 +1,106 @@ + + + + {currentStep?.title} + + {#if currentStep?.name === STEP_FORM} + + {/if} + {#if currentStep?.name === STEP_REVIEW && nonNullish(ledgerCanisterId) && nonNullish(tokenMetaData)} + + {/if} + From ffecb60c36c80060df80f828a660eb2e785cbca6 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 31 Jul 2024 11:25:36 +0200 Subject: [PATCH 053/166] feat: display the modal on import token click --- frontend/src/lib/pages/Tokens.svelte | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/frontend/src/lib/pages/Tokens.svelte b/frontend/src/lib/pages/Tokens.svelte index 6c11737f20d..92e3c231ca5 100644 --- a/frontend/src/lib/pages/Tokens.svelte +++ b/frontend/src/lib/pages/Tokens.svelte @@ -11,6 +11,7 @@ import { Popover } from "@dfinity/gix-components"; import { TokenAmountV2 } from "@dfinity/utils"; import { ENABLE_IMPORT_TOKEN } from "$lib/stores/feature-flags.store"; + import ImportTokenModal from "$lib/modals/accounts/ImportTokenModal.svelte"; export let userTokensData: UserToken[]; @@ -41,9 +42,7 @@ hideZeroBalancesStore.set("show"); }; - const importToken = async () => { - // TBD: Implement import token. - }; + let showImportTokenModal = false; // TODO(Import token): After removing ENABLE_IMPORT_TOKEN combine divs -> @@ -82,9 +81,9 @@ (showImportTokenModal = true)} > - {$i18n.tokens.import_token} + {$i18n.import_token.import_token} {:else if shouldHideZeroBalances} @@ -112,6 +111,10 @@ > + + {#if showImportTokenModal} + (showImportTokenModal = false)} /> + {/if} diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index 38c330178d3..84e839b68ef 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -1051,6 +1051,7 @@ "warning": "Warning: Be careful what token you import! Anyone can create a token including one with the same name as existing tokens, such as ckBTC.", "verifying": "Veryifying token details...", "importing": "Importing new token...", + "removing": "Removing imported token...", "review_token_info": "Review token info", "import_button": "Import", "ledger_canister_loading_error": "Unable to load token details using the provided Ledger Canister ID.", diff --git a/frontend/src/lib/services/imported-tokens.services.ts b/frontend/src/lib/services/imported-tokens.services.ts index b5f61ee0e51..0f05de23f4d 100644 --- a/frontend/src/lib/services/imported-tokens.services.ts +++ b/frontend/src/lib/services/imported-tokens.services.ts @@ -135,9 +135,12 @@ export const removeImportedTokens = async ({ tokensToRemove: ImportedTokenData[]; importedTokens: ImportedTokenData[]; }): Promise<{ success: boolean }> => { + const canisterIdsToRemove = tokensToRemove.map( + ({ ledgerCanisterId }) => ledgerCanisterId + ); // Compare imported tokens by their ledgerCanisterId because they should be unique. const ledgerIdsToRemove = new Set( - tokensToRemove.map(({ ledgerCanisterId }) => ledgerCanisterId.toText()) + canisterIdsToRemove.map((id) => id.toText()) ); const tokens = importedTokens.filter( ({ ledgerCanisterId }) => !ledgerIdsToRemove.has(ledgerCanisterId.toText()) @@ -145,6 +148,9 @@ export const removeImportedTokens = async ({ const { err } = await saveImportedToken({ tokens }); if (isNullish(err)) { + // TODO: update unit test to check if icrcCanistersStore.removeCanisters is called + icrcCanistersStore.removeCanisters(canisterIdsToRemove); + await loadImportedTokens(); toastsSuccess({ labelKey: "import_token.remove_imported_token_success", diff --git a/frontend/src/lib/stores/busy.store.ts b/frontend/src/lib/stores/busy.store.ts index 4edec0f7805..986f40dff4a 100644 --- a/frontend/src/lib/stores/busy.store.ts +++ b/frontend/src/lib/stores/busy.store.ts @@ -47,7 +47,8 @@ export type BusyStateInitiatorType = | "update-ckbtc-balance" | "reload-receive-account" | "import-token-validation" - | "import-token-importing"; + | "import-token-importing" + | "import-token-removing"; export interface BusyState { initiator: BusyStateInitiatorType; diff --git a/frontend/src/lib/stores/icrc-canisters.store.ts b/frontend/src/lib/stores/icrc-canisters.store.ts index 85201addc8c..c8e21b2317b 100644 --- a/frontend/src/lib/stores/icrc-canisters.store.ts +++ b/frontend/src/lib/stores/icrc-canisters.store.ts @@ -1,5 +1,6 @@ import { browser } from "$app/environment"; import type { UniverseCanisterIdText } from "$lib/types/universe"; +import { removeKeys } from "$lib/utils/utils"; import { Principal } from "@dfinity/principal"; import { nonNullish } from "@dfinity/utils"; import type { Readable } from "svelte/store"; @@ -17,6 +18,7 @@ export type IcrcCanistersStoreData = Record< export interface IcrcCanistersStore extends Readable { setCanisters: (data: IcrcCanisters) => void; + removeCanisters: (ledgerCanisterIds: Principal[]) => void; reset: () => void; } @@ -48,6 +50,17 @@ const initIcrcCanistersStore = (): IcrcCanistersStore => { })); }, + // TODO: unit test me! + // Remove entries by ledger canister id. + removeCanisters(ledgerCanisterIds: Principal[]) { + update((state: IcrcCanistersStoreData) => + removeKeys({ + obj: state, + keysToRemove: ledgerCanisterIds.map((id) => id.toText()), + }) + ); + }, + // Used in tests reset() { set(initialIcrcCanistersStoreData); From 1f576738e213106b1bcf87c24bfa7581602f6e0c Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 1 Aug 2024 16:23:08 +0200 Subject: [PATCH 085/166] chore: formatting --- .../components/accounts/IcrcWalletPage.svelte | 21 ++++++++++--------- .../modals/accounts/ImportTokenModal.svelte | 18 +++++++++------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte index 9cf1615e02c..e527d6e0073 100644 --- a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte +++ b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte @@ -24,10 +24,10 @@ import type { Principal } from "@dfinity/principal"; import { TokenAmountV2, isNullish, nonNullish } from "@dfinity/utils"; import type { Writable } from "svelte/store"; - import {accountsPathStore} from "$lib/derived/paths.derived"; - import {startBusy, stopBusy} from "$lib/stores/busy.store"; - import {importedTokensStore} from "$lib/stores/imported-tokens.store"; - import {removeImportedTokens} from "$lib/services/imported-tokens.services"; + import { accountsPathStore } from "$lib/derived/paths.derived"; + import { startBusy, stopBusy } from "$lib/stores/busy.store"; + import { importedTokensStore } from "$lib/stores/imported-tokens.store"; + import { removeImportedTokens } from "$lib/services/imported-tokens.services"; export let testId: string; export let accountIdentifier: string | undefined | null = undefined; @@ -147,7 +147,9 @@ isSignedIn: $authSignedInStore, }))(); - const remove = async ({ detail }: CustomEvent<{ledgerCanisterId: Principal}>) => { + const remove = async ({ + detail, + }: CustomEvent<{ ledgerCanisterId: Principal }>) => { console.log("removeImportedToken", detail.ledgerCanisterId); startBusy({ @@ -156,9 +158,10 @@ }); const importedTokens = $importedTokensStore.importedTokens ?? []; - const {success} = await removeImportedTokens({ + const { success } = await removeImportedTokens({ tokensToRemove: importedTokens.filter( - ({ledgerCanisterId: id}) => id.toText() === detail.ledgerCanisterId.toText() + ({ ledgerCanisterId: id }) => + id.toText() === detail.ledgerCanisterId.toText() ), importedTokens, }); @@ -168,9 +171,7 @@ if (success) { goto($accountsPathStore); } - - } - + }; diff --git a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte index 8f5aab0a87c..a0f544baa63 100644 --- a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte +++ b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte @@ -13,11 +13,11 @@ import { startBusy, stopBusy } from "$lib/stores/busy.store"; import { fetchIcrcTokenMetaData } from "$lib/services/icrc-accounts.services"; import { toastsError } from "$lib/stores/toasts.store"; - import {importedTokensStore} from "$lib/stores/imported-tokens.store"; - import {addImportedToken} from "$lib/services/imported-tokens.services"; - import {buildWalletUrl} from "$lib/utils/navigation.utils"; - import {goto} from "$app/navigation"; - import {createEventDispatcher} from "svelte"; + import { importedTokensStore } from "$lib/stores/imported-tokens.store"; + import { addImportedToken } from "$lib/services/imported-tokens.services"; + import { buildWalletUrl } from "$lib/utils/navigation.utils"; + import { goto } from "$app/navigation"; + import { createEventDispatcher } from "svelte"; let currentStep: WizardStep | undefined = undefined; const dispatch = createEventDispatcher(); @@ -104,9 +104,11 @@ dispatch("nnsClose"); - goto(buildWalletUrl({ - universe: ledgerCanisterId.toText(), - })); + goto( + buildWalletUrl({ + universe: ledgerCanisterId.toText(), + }) + ); stopBusy("import-token-importing"); }; From 9d6ca11b76c5c09fe52106244354d9276ac36df8 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 1 Aug 2024 16:51:37 +0200 Subject: [PATCH 086/166] fix: update i18n types --- frontend/src/lib/types/i18n.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/lib/types/i18n.d.ts b/frontend/src/lib/types/i18n.d.ts index d250517353d..e156b8cbc13 100644 --- a/frontend/src/lib/types/i18n.d.ts +++ b/frontend/src/lib/types/i18n.d.ts @@ -1112,6 +1112,7 @@ interface I18nImport_token { warning: string; verifying: string; importing: string; + removing: string; review_token_info: string; import_button: string; ledger_canister_loading_error: string; From 4654cc055acbbee0052f2afc311ed1033ae64ce8 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 1 Aug 2024 16:51:57 +0200 Subject: [PATCH 087/166] test: fix compareTokensByImportance arguments --- frontend/src/tests/lib/utils/tokens-table.utils.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts index ea02a064f85..f0b8b821ce6 100644 --- a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts +++ b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts @@ -100,17 +100,17 @@ describe("tokens-table.utils", () => { const expectedOrder = [ckBTCToken, ckETHTToken, ckUSDCToken, token0]; expect( [token0, ckUSDCToken, ckETHTToken, ckBTCToken].sort( - compareTokensByImportance + compareTokensByImportance({ importedTokenIds: new Set() }) ) ).toEqual(expectedOrder); expect( [ckBTCToken, ckETHTToken, ckUSDCToken, token0].sort( - compareTokensByImportance + compareTokensByImportance({ importedTokenIds: new Set() }) ) ).toEqual(expectedOrder); expect( [ckETHTToken, ckBTCToken, token0, ckUSDCToken].sort( - compareTokensByImportance + compareTokensByImportance({ importedTokenIds: new Set() }) ) ).toEqual(expectedOrder); }); From 234b0d48b474d27de5d3a1a107560ae77d6b292a Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 1 Aug 2024 17:07:36 +0200 Subject: [PATCH 088/166] test: adjust "should not show errors if loading accounts fails" test --- frontend/src/tests/lib/services/app.services.spec.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/frontend/src/tests/lib/services/app.services.spec.ts b/frontend/src/tests/lib/services/app.services.spec.ts index 970e5913594..e41c6d0caaa 100644 --- a/frontend/src/tests/lib/services/app.services.spec.ts +++ b/frontend/src/tests/lib/services/app.services.spec.ts @@ -83,7 +83,16 @@ describe("app-services", () => { await expect(mockLedgerCanister.accountBalance).not.toBeCalled(); const toastData = get(toastsStore); - expect(toastData).toHaveLength(0); + + // The imported tokens error should be shown. + // TODO: check if this is the correct behavior + expect(toastData).toHaveLength(1); + expect(toastData).toEqual([ + expect.objectContaining({ + text: "There was an unexpected issue while loading imported tokens. Cannot read properties of undefined (reading 'imported_tokens')", + level: "error", + }), + ]); }); it("should call loadActionableProposals after Sns data is ready", async () => { From 03a0b6989ca110af04f6ef71ee07a9b84acc760b Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 1 Aug 2024 18:05:50 +0200 Subject: [PATCH 089/166] chore: remove log --- frontend/src/lib/services/imported-tokens.services.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/lib/services/imported-tokens.services.ts b/frontend/src/lib/services/imported-tokens.services.ts index 0f05de23f4d..37317ec3a23 100644 --- a/frontend/src/lib/services/imported-tokens.services.ts +++ b/frontend/src/lib/services/imported-tokens.services.ts @@ -29,7 +29,6 @@ export const loadImportedTokens = async () => { strategy: FORCE_CALL_STRATEGY, onLoad: ({ response: { imported_tokens: rawImportTokens }, certified }) => { const importedTokens = rawImportTokens.map(toImportedTokenData); - console.log("User Imported Tokens:", importedTokens); importedTokensStore.set({ importedTokens, certified, From 0179f680782485934d98e3896c17a12b1b25f312 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 1 Aug 2024 18:24:08 +0200 Subject: [PATCH 090/166] ! ENABLE ENABLE_IMPORT_TOKEN FLAG ! For testing on beta --- dfx.json | 2 +- scripts/nns-dapp/test-config-assets/app/arg.did | 2 +- scripts/nns-dapp/test-config-assets/app/env | 2 +- scripts/nns-dapp/test-config-assets/mainnet/arg.did | 2 +- scripts/nns-dapp/test-config-assets/mainnet/env | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dfx.json b/dfx.json index db88e09e49e..8a5dd1e08b3 100644 --- a/dfx.json +++ b/dfx.json @@ -372,7 +372,7 @@ "ENABLE_CKBTC": true, "ENABLE_CKTESTBTC": false, "ENABLE_PROJECTS_TABLE": true, - "ENABLE_IMPORT_TOKEN": false + "ENABLE_IMPORT_TOKEN": true } } }, diff --git a/scripts/nns-dapp/test-config-assets/app/arg.did b/scripts/nns-dapp/test-config-assets/app/arg.did index 5a2452b00a3..5f28822458e 100644 --- a/scripts/nns-dapp/test-config-assets/app/arg.did +++ b/scripts/nns-dapp/test-config-assets/app/arg.did @@ -10,7 +10,7 @@ record{ 0="CKUSDC_LEDGER_CANISTER_ID"; 1="xevnm-gaaaa-aaaar-qafnq-cai" }; record{ 0="CYCLES_MINTING_CANISTER_ID"; 1="rkp4c-7iaaa-aaaaa-aaaca-cai" }; record{ 0="DFX_NETWORK"; 1="app" }; - record{ 0="FEATURE_FLAGS"; 1="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":false,\"ENABLE_PROJECTS_TABLE\":true}" }; + record{ 0="FEATURE_FLAGS"; 1="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":true,\"ENABLE_PROJECTS_TABLE\":true}" }; record{ 0="FETCH_ROOT_KEY"; 1="false" }; record{ 0="GOVERNANCE_CANISTER_ID"; 1="rrkah-fqaaa-aaaaa-aaaaq-cai" }; record{ 0="HOST"; 1="https://icp-api.io" }; diff --git a/scripts/nns-dapp/test-config-assets/app/env b/scripts/nns-dapp/test-config-assets/app/env index 9ac6d3f20f4..218bffd98bd 100644 --- a/scripts/nns-dapp/test-config-assets/app/env +++ b/scripts/nns-dapp/test-config-assets/app/env @@ -7,7 +7,7 @@ VITE_LEDGER_CANISTER_ID=ryjl3-tyaaa-aaaaa-aaaba-cai VITE_INDEX_CANISTER_ID=qhbym-qaaaa-aaaaa-aaafq-cai VITE_OWN_CANISTER_ID=xnjld-hqaaa-aaaal-qb56q-cai VITE_FETCH_ROOT_KEY=false -VITE_FEATURE_FLAGS="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":false,\"ENABLE_PROJECTS_TABLE\":true}" +VITE_FEATURE_FLAGS="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":true,\"ENABLE_PROJECTS_TABLE\":true}" VITE_HOST=https://icp-api.io VITE_IDENTITY_SERVICE_URL=https://identity.internetcomputer.org/ VITE_AGGREGATOR_CANISTER_URL=https://otgyv-wyaaa-aaaak-qcgba-cai.icp0.io diff --git a/scripts/nns-dapp/test-config-assets/mainnet/arg.did b/scripts/nns-dapp/test-config-assets/mainnet/arg.did index 9d045bd37df..d665c4f434e 100644 --- a/scripts/nns-dapp/test-config-assets/mainnet/arg.did +++ b/scripts/nns-dapp/test-config-assets/mainnet/arg.did @@ -10,7 +10,7 @@ record{ 0="CKUSDC_LEDGER_CANISTER_ID"; 1="xevnm-gaaaa-aaaar-qafnq-cai" }; record{ 0="CYCLES_MINTING_CANISTER_ID"; 1="rkp4c-7iaaa-aaaaa-aaaca-cai" }; record{ 0="DFX_NETWORK"; 1="mainnet" }; - record{ 0="FEATURE_FLAGS"; 1="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":false,\"ENABLE_PROJECTS_TABLE\":true}" }; + record{ 0="FEATURE_FLAGS"; 1="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":true,\"ENABLE_PROJECTS_TABLE\":true}" }; record{ 0="FETCH_ROOT_KEY"; 1="false" }; record{ 0="GOVERNANCE_CANISTER_ID"; 1="rrkah-fqaaa-aaaaa-aaaaq-cai" }; record{ 0="HOST"; 1="https://icp-api.io" }; diff --git a/scripts/nns-dapp/test-config-assets/mainnet/env b/scripts/nns-dapp/test-config-assets/mainnet/env index a429fa8f7e4..dd40cfdc387 100644 --- a/scripts/nns-dapp/test-config-assets/mainnet/env +++ b/scripts/nns-dapp/test-config-assets/mainnet/env @@ -7,7 +7,7 @@ VITE_LEDGER_CANISTER_ID=ryjl3-tyaaa-aaaaa-aaaba-cai VITE_INDEX_CANISTER_ID=qhbym-qaaaa-aaaaa-aaafq-cai VITE_OWN_CANISTER_ID=qoctq-giaaa-aaaaa-aaaea-cai VITE_FETCH_ROOT_KEY=false -VITE_FEATURE_FLAGS="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":false,\"ENABLE_PROJECTS_TABLE\":true}" +VITE_FEATURE_FLAGS="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":true,\"ENABLE_PROJECTS_TABLE\":true}" VITE_HOST=https://icp-api.io VITE_IDENTITY_SERVICE_URL=https://identity.internetcomputer.org/ VITE_AGGREGATOR_CANISTER_URL=https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io From 9164fcf348ff992cec1fa70eb6b142d5c4c237e0 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 1 Aug 2024 20:30:03 +0200 Subject: [PATCH 091/166] Temporary suppress load imported tokens error toast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise, it’s always present in the CI, which breaks the e2e tests. --- frontend/src/lib/services/imported-tokens.services.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/src/lib/services/imported-tokens.services.ts b/frontend/src/lib/services/imported-tokens.services.ts index 37317ec3a23..484350a4895 100644 --- a/frontend/src/lib/services/imported-tokens.services.ts +++ b/frontend/src/lib/services/imported-tokens.services.ts @@ -54,10 +54,11 @@ export const loadImportedTokens = async () => { // Explicitly handle only UPDATE errors importedTokensStore.reset(); - toastsError({ - labelKey: "error__imported_tokens.load_imported_tokens", - err, - }); + // TODO: uncomment this after api availability on CI + // toastsError({ + // labelKey: "error__imported_tokens.load_imported_tokens", + // err, + // }); }, logMessage: "Get Imported Tokens", }); From ada4b18f80a126238fc8777829dd666d2cba3150 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 1 Aug 2024 20:58:20 +0200 Subject: [PATCH 092/166] Temporary suppress load imported tokens error toast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise, it’s always present in the CI, which breaks the e2e tests. --- .../src/tests/lib/services/app.services.spec.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/frontend/src/tests/lib/services/app.services.spec.ts b/frontend/src/tests/lib/services/app.services.spec.ts index e41c6d0caaa..f28de7fa085 100644 --- a/frontend/src/tests/lib/services/app.services.spec.ts +++ b/frontend/src/tests/lib/services/app.services.spec.ts @@ -84,15 +84,16 @@ describe("app-services", () => { const toastData = get(toastsStore); + expect(toastData).toHaveLength(0); // The imported tokens error should be shown. // TODO: check if this is the correct behavior - expect(toastData).toHaveLength(1); - expect(toastData).toEqual([ - expect.objectContaining({ - text: "There was an unexpected issue while loading imported tokens. Cannot read properties of undefined (reading 'imported_tokens')", - level: "error", - }), - ]); + // expect(toastData).toHaveLength(1); + // expect(toastData).toEqual([ + // expect.objectContaining({ + // text: "There was an unexpected issue while loading imported tokens. Cannot read properties of undefined (reading 'imported_tokens')", + // level: "error", + // }), + // ]); }); it("should call loadActionableProposals after Sns data is ready", async () => { From 19515aebc0813cbf8892878f18c308114cda7276 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 1 Aug 2024 22:15:22 +0200 Subject: [PATCH 093/166] Temporary suppress load imported tokens error toast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise, it’s always present in the CI, which breaks the e2e tests. --- .../lib/services/imported-tokens.services.spec.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend/src/tests/lib/services/imported-tokens.services.spec.ts b/frontend/src/tests/lib/services/imported-tokens.services.spec.ts index a00e4448db4..d715e9504c0 100644 --- a/frontend/src/tests/lib/services/imported-tokens.services.spec.ts +++ b/frontend/src/tests/lib/services/imported-tokens.services.spec.ts @@ -82,11 +82,13 @@ describe("imported-tokens-services", () => { await loadImportedTokens(); - expect(spyToastError).toBeCalledTimes(1); - expect(spyToastError).toBeCalledWith({ - labelKey: "error__imported_tokens.load_imported_tokens", - err: testError, - }); + // TODO: uncomment this after api availability on CI + expect(spyToastError).toBeCalledTimes(0); + // expect(spyToastError).toBeCalledTimes(1); + // expect(spyToastError).toBeCalledWith({ + // labelKey: "error__imported_tokens.load_imported_tokens", + // err: testError, + // }); }); it("should reset store on error", async () => { From 54194d17797406233af25c424da87c46c8892391 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 2 Aug 2024 08:50:15 +0200 Subject: [PATCH 094/166] i18n: update new account description to "Create a new account controlled by your Ledger device" --- frontend/src/lib/i18n/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index 84e839b68ef..b268ac3727d 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -168,7 +168,7 @@ "new_account_title": "New Account", "new_linked_subtitle": "Create a new account controlled by your Internet Identity", "attach_hardware_title": "New Account (Hardware Wallet)", - "attach_hardware_subtitle": "Create a new account controlled by your hardware wallet", + "attach_hardware_subtitle": "Create a new account controlled by your Ledger device", "attach_hardware_name_placeholder": "Hardware Wallet Name", "attach_hardware_enter_name": "Enter Wallet Name", "attach_hardware_description": "Create a new account controlled by your connected hardware wallet.", From 5540cb7bb8064f3de98be08204f5d5eb5d9f487d Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 2 Aug 2024 08:52:20 +0200 Subject: [PATCH 095/166] i18n: capitalise Ledger everywhere because it's a proper noun. --- frontend/src/lib/i18n/en.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index b268ac3727d..1cc359719eb 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -799,19 +799,19 @@ }, "error__ledger": { "unexpected": "There was an error with the hardware wallet.", - "app_version_not_supported": "This Ledger device is running an outdated version of the Internet Computer app. In order to use the device with this application, it needs to be updated to version 2.4.9 or later. More info here.", + "app_version_not_supported": "This Ledger device is running an outdated version of the Internet Computer app. In order to use the device with this application, it needs to be updated to version 2.4.9 or later. More info here.", "please_open": "Please open the Internet Computer app on your hardware wallet and try again.", "locked": "Hardware Wallet is locked. Unlock it and try again.", "fetch_public_key": "Unable to fetch the public key. Please try again.", "principal_not_match": "Principal returned by the device does not match the public key.", - "signature_unexpected": "A ledger error happened during signature. $message (code $code).", + "signature_unexpected": "A Ledger error happened during signature. $message (code $code).", "signature_length": "Signature must be 64 bytes long (is $length)", "connect_no_device": "No hardware wallet found. Is the hardware wallet connected and unlocked?", "connect_many_apps": "Cannot connect to the hardware wallet. Please close all other wallet applications (e.g. Ledger Live) and try again.", "connect_not_supported": "Either you have other wallet applications open (e.g. Ledger Live), or your browser doesn't support WebHID, which is necessary to communicate with your Ledger hardware wallet. Supported browsers: Chrome (Desktop) v89+, Edge v89+, Opera v76+. Error: $err", "unexpected_wallet": "Found unexpected public key. Are you sure you're using the right hardware wallet?", - "access_denied": "Access denied to use the ledger device.", - "user_rejected_transaction": "The transaction was rejected on the ledger device.", + "access_denied": "Access denied to use the Ledger device.", + "user_rejected_transaction": "The transaction was rejected on the Ledger device.", "version_not_supported": "Sorry, transaction not supported with version $currentVersion. Please upgrade the Internet Computer app on your Ledger device to at least version $minVersion.", "browser_not_supported": "Sorry, the browser does not support the WebHID API needed to connect the hardware wallet. Check support in https://caniuse.com/?search=WebHID", "incorrect_identifier": "Wallet account identifier doesn't match. Are you sure you connected the right hardware wallet? Expected identifier: $identifier. Wallet identifier: $ledgerIdentifier." @@ -884,7 +884,7 @@ "sns_sale_invalid_subaccount": "Can't participate with the selected subaccount.", "sns_sale_try_later": "Sorry, there was an unexpected error while participating. Please try again later.", "sns_sale_committed_not_equal_to_amount": "Your total committed: $amount ICP", - "ledger_temporarily_unavailable": "Sorry, the ledger is not available at the moment. Please try again later.", + "ledger_temporarily_unavailable": "Sorry, the Ledger is not available at the moment. Please try again later.", "ledger_duplicate": "Sorry, the transaction is duplicated. Please try again.", "ledger_bad_fee": "Sorry, wrong transaction fee applied. Please try again.", "ledger_created_future": "Sorry, the transaction can't be created in the future. Please try again.", @@ -1041,7 +1041,7 @@ "import_token": { "import_token": "Import Token", "imported_token": "Imported Token", - "description": "To import a new token to your NNS dapp wallet, you will need to find, and paste the ledger canister id of the token. If you want to see your transaction history, you need to import the token’s index canister.", + "description": "To import a new token to your NNS dapp wallet, you will need to find, and paste the Ledger canister id of the token. If you want to see your transaction history, you need to import the token’s index canister.", "ledger_label": "Ledger Canister ID", "index_label_optional": "Index Canister ID (Optional)", "index_label": "Index Canister ID", From 783fcf2c8e1dc17dade489d5473ffd7dca857a38 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 2 Aug 2024 08:57:55 +0200 Subject: [PATCH 096/166] Adjust unit test because of the label update --- frontend/src/tests/lib/utils/ledger.utils.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/tests/lib/utils/ledger.utils.spec.ts b/frontend/src/tests/lib/utils/ledger.utils.spec.ts index 17803267a63..efc24b49e80 100644 --- a/frontend/src/tests/lib/utils/ledger.utils.spec.ts +++ b/frontend/src/tests/lib/utils/ledger.utils.spec.ts @@ -95,7 +95,7 @@ describe("ledger-utils", () => { expect(call).rejects.toThrow( new LedgerErrorMessage( - `A ledger error happened during signature. undefined (code ${LedgerError.UnknownError}).` + `A Ledger error happened during signature. undefined (code ${LedgerError.UnknownError}).` ) ); }); From 9626542a44ef1c501ee87add181edc2cb282fe81 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 2 Aug 2024 14:51:19 +0200 Subject: [PATCH 097/166] i18n: change "Add hardware account" button title --- frontend/src/lib/i18n/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index 1cc359719eb..2ccacc99e26 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -167,8 +167,8 @@ "add_account": "Add Account", "new_account_title": "New Account", "new_linked_subtitle": "Create a new account controlled by your Internet Identity", - "attach_hardware_title": "New Account (Hardware Wallet)", "attach_hardware_subtitle": "Create a new account controlled by your Ledger device", + "attach_hardware_title": "New Account (Ledger Controlled)", "attach_hardware_name_placeholder": "Hardware Wallet Name", "attach_hardware_enter_name": "Enter Wallet Name", "attach_hardware_description": "Create a new account controlled by your connected hardware wallet.", From 196589fda45d580e9547681a43191588653bb373 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 2 Aug 2024 14:55:09 +0200 Subject: [PATCH 098/166] Update test environment warning. --- .../warnings/TestEnvironmentWarning.svelte | 16 ++++++++-------- frontend/src/lib/i18n/en.json | 4 +--- frontend/src/lib/types/i18n.d.ts | 4 +--- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/frontend/src/lib/components/warnings/TestEnvironmentWarning.svelte b/frontend/src/lib/components/warnings/TestEnvironmentWarning.svelte index 524633de7d0..42f675c8730 100644 --- a/frontend/src/lib/components/warnings/TestEnvironmentWarning.svelte +++ b/frontend/src/lib/components/warnings/TestEnvironmentWarning.svelte @@ -20,22 +20,18 @@ disablePointerEvents={true} > - + + + {$i18n.warning.test_env_title} - {$i18n.warning.test_env_welcome} - - - {$i18n.warning.test_env_request} - - - {$i18n.warning.test_env_confirm} @@ -53,4 +49,8 @@ justify-content: center; padding: var(--padding-2x) 0 var(--padding); } + + p { + padding: 0 var(--padding); + } diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index 2ccacc99e26..ef99d334cb3 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -123,9 +123,7 @@ }, "warning": { "auth_sign_out": "You have been logged out because your session has expired.", - "test_env_welcome": "Welcome to the Testing Environment.", - "test_env_note": "Please note that you are currently using a test version of NNS-dapp that operates on the Internet Computer mainnet. Although it utilizes real data, it is intended solely for testing purposes.", - "test_env_request": "We kindly remind you that the functionality and availability of this testing dapp may change or even disappear at any time. Therefore, it is crucial to refrain from relying on it for any production or critical activities.", + "test_env_note": "Use with caution! This is not stable software, and it is not securely updated by the Network Nervous System. However, it accesses your real wallets and neurons. Functionality you see here can change at any time, and this dapp may not always be available.", "test_env_confirm": "I understand and want to continue", "test_env_title": "Warning" }, diff --git a/frontend/src/lib/types/i18n.d.ts b/frontend/src/lib/types/i18n.d.ts index e156b8cbc13..13b1c7e66c2 100644 --- a/frontend/src/lib/types/i18n.d.ts +++ b/frontend/src/lib/types/i18n.d.ts @@ -128,9 +128,7 @@ interface I18nError { interface I18nWarning { auth_sign_out: string; - test_env_welcome: string; test_env_note: string; - test_env_request: string; test_env_confirm: string; test_env_title: string; } @@ -176,8 +174,8 @@ interface I18nAccounts { add_account: string; new_account_title: string; new_linked_subtitle: string; - attach_hardware_title: string; attach_hardware_subtitle: string; + attach_hardware_title: string; attach_hardware_name_placeholder: string; attach_hardware_enter_name: string; attach_hardware_description: string; From ac5947dec2f35977fd3cc468340ce1a34ba57ea5 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Sun, 4 Aug 2024 10:33:45 +0200 Subject: [PATCH 099/166] Revert "Temporary suppress load imported tokens error toast" This reverts commit 19515aebc0813cbf8892878f18c308114cda7276. --- .../lib/services/imported-tokens.services.spec.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/frontend/src/tests/lib/services/imported-tokens.services.spec.ts b/frontend/src/tests/lib/services/imported-tokens.services.spec.ts index d715e9504c0..a00e4448db4 100644 --- a/frontend/src/tests/lib/services/imported-tokens.services.spec.ts +++ b/frontend/src/tests/lib/services/imported-tokens.services.spec.ts @@ -82,13 +82,11 @@ describe("imported-tokens-services", () => { await loadImportedTokens(); - // TODO: uncomment this after api availability on CI - expect(spyToastError).toBeCalledTimes(0); - // expect(spyToastError).toBeCalledTimes(1); - // expect(spyToastError).toBeCalledWith({ - // labelKey: "error__imported_tokens.load_imported_tokens", - // err: testError, - // }); + expect(spyToastError).toBeCalledTimes(1); + expect(spyToastError).toBeCalledWith({ + labelKey: "error__imported_tokens.load_imported_tokens", + err: testError, + }); }); it("should reset store on error", async () => { From c23a67cdf5a20436c84c09f3d3a62e14c6245dc8 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Sun, 4 Aug 2024 10:35:31 +0200 Subject: [PATCH 100/166] Revert "Temporary suppress load imported tokens error toast" This reverts commit ada4b18f80a126238fc8777829dd666d2cba3150. --- .../src/tests/lib/services/app.services.spec.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/frontend/src/tests/lib/services/app.services.spec.ts b/frontend/src/tests/lib/services/app.services.spec.ts index f28de7fa085..e41c6d0caaa 100644 --- a/frontend/src/tests/lib/services/app.services.spec.ts +++ b/frontend/src/tests/lib/services/app.services.spec.ts @@ -84,16 +84,15 @@ describe("app-services", () => { const toastData = get(toastsStore); - expect(toastData).toHaveLength(0); // The imported tokens error should be shown. // TODO: check if this is the correct behavior - // expect(toastData).toHaveLength(1); - // expect(toastData).toEqual([ - // expect.objectContaining({ - // text: "There was an unexpected issue while loading imported tokens. Cannot read properties of undefined (reading 'imported_tokens')", - // level: "error", - // }), - // ]); + expect(toastData).toHaveLength(1); + expect(toastData).toEqual([ + expect.objectContaining({ + text: "There was an unexpected issue while loading imported tokens. Cannot read properties of undefined (reading 'imported_tokens')", + level: "error", + }), + ]); }); it("should call loadActionableProposals after Sns data is ready", async () => { From ce4a3117152ff86a1359bf4c83b6192cc9f01263 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Sun, 4 Aug 2024 10:35:42 +0200 Subject: [PATCH 101/166] Revert "Temporary suppress load imported tokens error toast" This reverts commit 9164fcf348ff992cec1fa70eb6b142d5c4c237e0. --- frontend/src/lib/services/imported-tokens.services.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/src/lib/services/imported-tokens.services.ts b/frontend/src/lib/services/imported-tokens.services.ts index 484350a4895..37317ec3a23 100644 --- a/frontend/src/lib/services/imported-tokens.services.ts +++ b/frontend/src/lib/services/imported-tokens.services.ts @@ -54,11 +54,10 @@ export const loadImportedTokens = async () => { // Explicitly handle only UPDATE errors importedTokensStore.reset(); - // TODO: uncomment this after api availability on CI - // toastsError({ - // labelKey: "error__imported_tokens.load_imported_tokens", - // err, - // }); + toastsError({ + labelKey: "error__imported_tokens.load_imported_tokens", + err, + }); }, logMessage: "Get Imported Tokens", }); From 4c3ba3473a6608f995ee9f55f5ad0e26dbe1b2e9 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Sun, 4 Aug 2024 10:35:52 +0200 Subject: [PATCH 102/166] Revert "! ENABLE ENABLE_IMPORT_TOKEN FLAG !" This reverts commit 0179f680782485934d98e3896c17a12b1b25f312. --- dfx.json | 2 +- scripts/nns-dapp/test-config-assets/app/arg.did | 2 +- scripts/nns-dapp/test-config-assets/app/env | 2 +- scripts/nns-dapp/test-config-assets/mainnet/arg.did | 2 +- scripts/nns-dapp/test-config-assets/mainnet/env | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dfx.json b/dfx.json index 8a5dd1e08b3..db88e09e49e 100644 --- a/dfx.json +++ b/dfx.json @@ -372,7 +372,7 @@ "ENABLE_CKBTC": true, "ENABLE_CKTESTBTC": false, "ENABLE_PROJECTS_TABLE": true, - "ENABLE_IMPORT_TOKEN": true + "ENABLE_IMPORT_TOKEN": false } } }, diff --git a/scripts/nns-dapp/test-config-assets/app/arg.did b/scripts/nns-dapp/test-config-assets/app/arg.did index 5f28822458e..5a2452b00a3 100644 --- a/scripts/nns-dapp/test-config-assets/app/arg.did +++ b/scripts/nns-dapp/test-config-assets/app/arg.did @@ -10,7 +10,7 @@ record{ 0="CKUSDC_LEDGER_CANISTER_ID"; 1="xevnm-gaaaa-aaaar-qafnq-cai" }; record{ 0="CYCLES_MINTING_CANISTER_ID"; 1="rkp4c-7iaaa-aaaaa-aaaca-cai" }; record{ 0="DFX_NETWORK"; 1="app" }; - record{ 0="FEATURE_FLAGS"; 1="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":true,\"ENABLE_PROJECTS_TABLE\":true}" }; + record{ 0="FEATURE_FLAGS"; 1="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":false,\"ENABLE_PROJECTS_TABLE\":true}" }; record{ 0="FETCH_ROOT_KEY"; 1="false" }; record{ 0="GOVERNANCE_CANISTER_ID"; 1="rrkah-fqaaa-aaaaa-aaaaq-cai" }; record{ 0="HOST"; 1="https://icp-api.io" }; diff --git a/scripts/nns-dapp/test-config-assets/app/env b/scripts/nns-dapp/test-config-assets/app/env index 218bffd98bd..9ac6d3f20f4 100644 --- a/scripts/nns-dapp/test-config-assets/app/env +++ b/scripts/nns-dapp/test-config-assets/app/env @@ -7,7 +7,7 @@ VITE_LEDGER_CANISTER_ID=ryjl3-tyaaa-aaaaa-aaaba-cai VITE_INDEX_CANISTER_ID=qhbym-qaaaa-aaaaa-aaafq-cai VITE_OWN_CANISTER_ID=xnjld-hqaaa-aaaal-qb56q-cai VITE_FETCH_ROOT_KEY=false -VITE_FEATURE_FLAGS="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":true,\"ENABLE_PROJECTS_TABLE\":true}" +VITE_FEATURE_FLAGS="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":false,\"ENABLE_PROJECTS_TABLE\":true}" VITE_HOST=https://icp-api.io VITE_IDENTITY_SERVICE_URL=https://identity.internetcomputer.org/ VITE_AGGREGATOR_CANISTER_URL=https://otgyv-wyaaa-aaaak-qcgba-cai.icp0.io diff --git a/scripts/nns-dapp/test-config-assets/mainnet/arg.did b/scripts/nns-dapp/test-config-assets/mainnet/arg.did index d665c4f434e..9d045bd37df 100644 --- a/scripts/nns-dapp/test-config-assets/mainnet/arg.did +++ b/scripts/nns-dapp/test-config-assets/mainnet/arg.did @@ -10,7 +10,7 @@ record{ 0="CKUSDC_LEDGER_CANISTER_ID"; 1="xevnm-gaaaa-aaaar-qafnq-cai" }; record{ 0="CYCLES_MINTING_CANISTER_ID"; 1="rkp4c-7iaaa-aaaaa-aaaca-cai" }; record{ 0="DFX_NETWORK"; 1="mainnet" }; - record{ 0="FEATURE_FLAGS"; 1="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":true,\"ENABLE_PROJECTS_TABLE\":true}" }; + record{ 0="FEATURE_FLAGS"; 1="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":false,\"ENABLE_PROJECTS_TABLE\":true}" }; record{ 0="FETCH_ROOT_KEY"; 1="false" }; record{ 0="GOVERNANCE_CANISTER_ID"; 1="rrkah-fqaaa-aaaaa-aaaaq-cai" }; record{ 0="HOST"; 1="https://icp-api.io" }; diff --git a/scripts/nns-dapp/test-config-assets/mainnet/env b/scripts/nns-dapp/test-config-assets/mainnet/env index dd40cfdc387..a429fa8f7e4 100644 --- a/scripts/nns-dapp/test-config-assets/mainnet/env +++ b/scripts/nns-dapp/test-config-assets/mainnet/env @@ -7,7 +7,7 @@ VITE_LEDGER_CANISTER_ID=ryjl3-tyaaa-aaaaa-aaaba-cai VITE_INDEX_CANISTER_ID=qhbym-qaaaa-aaaaa-aaafq-cai VITE_OWN_CANISTER_ID=qoctq-giaaa-aaaaa-aaaea-cai VITE_FETCH_ROOT_KEY=false -VITE_FEATURE_FLAGS="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":true,\"ENABLE_PROJECTS_TABLE\":true}" +VITE_FEATURE_FLAGS="{\"ENABLE_CKBTC\":true,\"ENABLE_CKTESTBTC\":false,\"ENABLE_IMPORT_TOKEN\":false,\"ENABLE_PROJECTS_TABLE\":true}" VITE_HOST=https://icp-api.io VITE_IDENTITY_SERVICE_URL=https://identity.internetcomputer.org/ VITE_AGGREGATOR_CANISTER_URL=https://3r4gx-wqaaa-aaaaq-aaaia-cai.icp0.io From d496799aaff8ad34d2b6e7f943fe5680a9f8b3fa Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Mon, 5 Aug 2024 14:18:42 +0200 Subject: [PATCH 103/166] feat: compareTokensByImportance comparator --- frontend/src/lib/utils/tokens-table.utils.ts | 21 ++++---------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/frontend/src/lib/utils/tokens-table.utils.ts b/frontend/src/lib/utils/tokens-table.utils.ts index f7c9b9c8eb1..9789076a4cd 100644 --- a/frontend/src/lib/utils/tokens-table.utils.ts +++ b/frontend/src/lib/utils/tokens-table.utils.ts @@ -21,7 +21,6 @@ export const compareTokensWithBalanceFirst = createDescendingComparator( (token: UserToken) => getTokenBalanceOrZero(token) > 0n ); -// TODO: add unit tests export const compareTokensWithBalanceOrImportedFirst = ({ importedTokenIds, }: { @@ -43,20 +42,9 @@ const ImportantCkTokenIds = [ ] // To place other tokens (which get an index of -1) at the bottom. .reverse(); -// TODO: update unit tests -export const compareTokensByImportance = ({ - importedTokenIds, -}: { - importedTokenIds: Set; -}) => - createDescendingComparator((token: UserToken) => { - const ckKnownIndex = ImportantCkTokenIds.indexOf(token.universeId.toText()); - if (ckKnownIndex >= 0) { - return ckKnownIndex; - } - - return importedTokenIds.has(token.universeId.toText()) ? 0 : -1; - }); +export const compareTokensByImportance = createDescendingComparator( + (token: UserToken) => ImportantCkTokenIds.indexOf(token.universeId.toText()) +); export const compareTokensAlphabetically = createAscendingComparator( ({ title }: UserToken) => title.toLowerCase() @@ -71,7 +59,6 @@ export const compareTokensForTokensTable = ({ mergeComparators([ compareTokensIcpFirst, compareTokensWithBalanceOrImportedFirst({ importedTokenIds }), - compareTokensWithBalanceFirst, - compareTokensByImportance({ importedTokenIds }), + compareTokensByImportance, compareTokensAlphabetically, ]); From 5c58c172c7c47cb79883903fbc2457f75d8d321f Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Mon, 5 Aug 2024 14:19:25 +0200 Subject: [PATCH 104/166] refactor: tokenWithBalance mock function to have id --- .../lib/utils/tokens-table.utils.spec.ts | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts index f0b8b821ce6..a1a982d3120 100644 --- a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts +++ b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts @@ -17,12 +17,12 @@ import { import { TokenAmountV2 } from "@dfinity/utils"; describe("tokens-table.utils", () => { - const tokenWithBalance = (amount: bigint) => + const tokenWithBalance = ({ id, amount }: { id: number; amount: bigint }) => createUserToken({ - universeId: principal(Number(amount)), + universeId: principal(id), balance: TokenAmountV2.fromUlps({ amount, - token: { name: `T${amount}`, symbol: `T${amount}`, decimals: 8 }, + token: { name: `T${id}`, symbol: `T${id}`, decimals: 8 }, }), }); const ckBTCToken = createUserToken({ @@ -54,26 +54,26 @@ describe("tokens-table.utils", () => { it("should keep tokens with balance first", () => { expect( compareTokensWithBalanceFirst( - tokenWithBalance(1n), - tokenWithBalance(0n) + tokenWithBalance({ id: 1, amount: 1n }), + tokenWithBalance({ id: 0, amount: 0n }) ) ).toEqual(-1); expect( compareTokensWithBalanceFirst( - tokenWithBalance(0n), - tokenWithBalance(1n) + tokenWithBalance({ id: 0, amount: 0n }), + tokenWithBalance({ id: 1, amount: 1n }) ) ).toEqual(1); expect( compareTokensWithBalanceFirst( - tokenWithBalance(0n), - tokenWithBalance(0n) + tokenWithBalance({ id: 0, amount: 0n }), + tokenWithBalance({ id: 0, amount: 0n }) ) ).toEqual(0); expect( compareTokensWithBalanceFirst( - tokenWithBalance(1n), - tokenWithBalance(1n) + tokenWithBalance({ id: 1, amount: 1n }), + tokenWithBalance({ id: 1, amount: 1n }) ) ).toEqual(0); }); @@ -82,12 +82,12 @@ describe("tokens-table.utils", () => { expect( compareTokensWithBalanceFirst( createUserTokenLoading(), - tokenWithBalance(1n) + tokenWithBalance({ id: 1, amount: 1n }) ) ).toEqual(1); expect( compareTokensWithBalanceFirst( - tokenWithBalance(1n), + tokenWithBalance({ id: 1, amount: 1n }), createUserTokenLoading() ) ).toEqual(-1); @@ -96,21 +96,21 @@ describe("tokens-table.utils", () => { describe("compareTokensByImportance", () => { it("should sort tokens by importance", () => { - const token0 = tokenWithBalance(0n); + const token0 = tokenWithBalance({ id: 0, amount: 0n }); const expectedOrder = [ckBTCToken, ckETHTToken, ckUSDCToken, token0]; expect( [token0, ckUSDCToken, ckETHTToken, ckBTCToken].sort( - compareTokensByImportance({ importedTokenIds: new Set() }) + compareTokensByImportance ) ).toEqual(expectedOrder); expect( [ckBTCToken, ckETHTToken, ckUSDCToken, token0].sort( - compareTokensByImportance({ importedTokenIds: new Set() }) + compareTokensByImportance ) ).toEqual(expectedOrder); expect( [ckETHTToken, ckBTCToken, token0, ckUSDCToken].sort( - compareTokensByImportance({ importedTokenIds: new Set() }) + compareTokensByImportance ) ).toEqual(expectedOrder); }); From eb50ce17fe66dab0194083773a0a6ede24525831 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Mon, 5 Aug 2024 14:19:35 +0200 Subject: [PATCH 105/166] test: compareTokensWithBalanceOrImportedFirst --- .../lib/utils/tokens-table.utils.spec.ts | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts index a1a982d3120..4c8e213aca5 100644 --- a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts +++ b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts @@ -6,6 +6,7 @@ import { compareTokensByImportance, compareTokensIcpFirst, compareTokensWithBalanceFirst, + compareTokensWithBalanceOrImportedFirst, } from "$lib/utils/tokens-table.utils"; import { principal } from "$tests/mocks/sns-projects.mock"; import { @@ -116,6 +117,76 @@ describe("tokens-table.utils", () => { }); }); + describe("compareTokensWithBalanceOrImportedFirst", () => { + const token0 = tokenWithBalance({ id: 0, amount: 0n }); + const token1 = tokenWithBalance({ id: 1, amount: 1n }); + const importedTokenWithBalance = tokenWithBalance({ id: 2, amount: 1n }); + const importedTokenNoBalance = tokenWithBalance({ id: 3, amount: 0n }); + const importedTokenIds = new Set([ + importedTokenWithBalance.universeId.toText(), + importedTokenNoBalance.universeId.toText(), + ]); + + it("should compare by balance", () => { + expect( + compareTokensWithBalanceOrImportedFirst({ + importedTokenIds, + })(token1, token0) + ).toEqual(-1); + expect( + compareTokensWithBalanceOrImportedFirst({ + importedTokenIds, + })(token0, token1) + ).toEqual(1); + expect( + compareTokensWithBalanceOrImportedFirst({ + importedTokenIds, + })(token1, token1) + ).toEqual(0); + expect( + compareTokensWithBalanceOrImportedFirst({ + importedTokenIds, + })(token0, token0) + ).toEqual(0); + }); + + it("should compare by imported", () => { + expect( + compareTokensWithBalanceOrImportedFirst({ + importedTokenIds, + })(importedTokenNoBalance, token0) + ).toEqual(-1); + expect( + compareTokensWithBalanceOrImportedFirst({ + importedTokenIds, + })(token0, importedTokenNoBalance) + ).toEqual(1); + expect( + compareTokensWithBalanceOrImportedFirst({ + importedTokenIds, + })(importedTokenWithBalance, importedTokenNoBalance) + ).toEqual(0); + }); + + it("should compare by balance and imported", () => { + expect( + compareTokensWithBalanceOrImportedFirst({ + importedTokenIds, + })(importedTokenNoBalance, token1) + ).toEqual(0); + expect( + compareTokensWithBalanceOrImportedFirst({ + importedTokenIds, + })(token0, importedTokenNoBalance) + ).toEqual(1); + expect( + compareTokensWithBalanceOrImportedFirst({ + importedTokenIds, + })(importedTokenWithBalance, token0) + ).toEqual(-1); + }); + }); + describe("compareTokensAlphabetically", () => { const annaToken = createUserToken({ title: "Anna" }); const arnyToken = createUserToken({ title: "Arny" }); From ee63a31e9331401fe9913cb79b3aae29020f2b9d Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Mon, 5 Aug 2024 14:20:34 +0200 Subject: [PATCH 106/166] Remove compareTokensWithBalanceFirst --- frontend/src/lib/utils/tokens-table.utils.ts | 4 -- .../lib/utils/tokens-table.utils.spec.ts | 46 ------------------- 2 files changed, 50 deletions(-) diff --git a/frontend/src/lib/utils/tokens-table.utils.ts b/frontend/src/lib/utils/tokens-table.utils.ts index 9789076a4cd..52898bfcfb9 100644 --- a/frontend/src/lib/utils/tokens-table.utils.ts +++ b/frontend/src/lib/utils/tokens-table.utils.ts @@ -17,10 +17,6 @@ export const compareTokensIcpFirst = createDescendingComparator( (token: UserToken) => token.universeId.toText() === OWN_CANISTER_ID_TEXT ); -export const compareTokensWithBalanceFirst = createDescendingComparator( - (token: UserToken) => getTokenBalanceOrZero(token) > 0n -); - export const compareTokensWithBalanceOrImportedFirst = ({ importedTokenIds, }: { diff --git a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts index 4c8e213aca5..daaa2d41388 100644 --- a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts +++ b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts @@ -5,7 +5,6 @@ import { compareTokensAlphabetically, compareTokensByImportance, compareTokensIcpFirst, - compareTokensWithBalanceFirst, compareTokensWithBalanceOrImportedFirst, } from "$lib/utils/tokens-table.utils"; import { principal } from "$tests/mocks/sns-projects.mock"; @@ -13,7 +12,6 @@ import { ckBTCTokenBase, createIcpUserToken, createUserToken, - createUserTokenLoading, } from "$tests/mocks/tokens-page.mock"; import { TokenAmountV2 } from "@dfinity/utils"; @@ -51,50 +49,6 @@ describe("tokens-table.utils", () => { }); }); - describe("compareTokensWithBalanceFirst", () => { - it("should keep tokens with balance first", () => { - expect( - compareTokensWithBalanceFirst( - tokenWithBalance({ id: 1, amount: 1n }), - tokenWithBalance({ id: 0, amount: 0n }) - ) - ).toEqual(-1); - expect( - compareTokensWithBalanceFirst( - tokenWithBalance({ id: 0, amount: 0n }), - tokenWithBalance({ id: 1, amount: 1n }) - ) - ).toEqual(1); - expect( - compareTokensWithBalanceFirst( - tokenWithBalance({ id: 0, amount: 0n }), - tokenWithBalance({ id: 0, amount: 0n }) - ) - ).toEqual(0); - expect( - compareTokensWithBalanceFirst( - tokenWithBalance({ id: 1, amount: 1n }), - tokenWithBalance({ id: 1, amount: 1n }) - ) - ).toEqual(0); - }); - - it("should treat token in loading state as having a balance of 0", () => { - expect( - compareTokensWithBalanceFirst( - createUserTokenLoading(), - tokenWithBalance({ id: 1, amount: 1n }) - ) - ).toEqual(1); - expect( - compareTokensWithBalanceFirst( - tokenWithBalance({ id: 1, amount: 1n }), - createUserTokenLoading() - ) - ).toEqual(-1); - }); - }); - describe("compareTokensByImportance", () => { it("should sort tokens by importance", () => { const token0 = tokenWithBalance({ id: 0, amount: 0n }); From ae8918a61b9fe8f6305e7423e3d42cb1b9988d62 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Tue, 6 Aug 2024 11:00:27 +0200 Subject: [PATCH 107/166] feat: handle import token error --- .../lib/modals/accounts/ImportTokenModal.svelte | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte index a0f544baa63..c8a3f34c43d 100644 --- a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte +++ b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte @@ -94,7 +94,7 @@ labelKey: "import_token.importing", }); - await addImportedToken({ + const { success } = await addImportedToken({ tokenToAdd: { ledgerCanisterId, indexCanisterId, @@ -102,13 +102,15 @@ importedTokens: $importedTokensStore.importedTokens, }); - dispatch("nnsClose"); + if (success) { + dispatch("nnsClose"); - goto( - buildWalletUrl({ - universe: ledgerCanisterId.toText(), - }) - ); + goto( + buildWalletUrl({ + universe: ledgerCanisterId.toText(), + }) + ); + } stopBusy("import-token-importing"); }; From 201ab7a75733c754c195542e06ad42aa118b79a5 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Tue, 6 Aug 2024 11:21:24 +0200 Subject: [PATCH 108/166] test: createTokenWithBalance util --- .../lib/utils/tokens-table.utils.spec.ts | 27 +++++++++---------- frontend/src/tests/mocks/tokens-page.mock.ts | 19 +++++++++++++ 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts index daaa2d41388..7ede83f1723 100644 --- a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts +++ b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts @@ -7,23 +7,14 @@ import { compareTokensIcpFirst, compareTokensWithBalanceOrImportedFirst, } from "$lib/utils/tokens-table.utils"; -import { principal } from "$tests/mocks/sns-projects.mock"; import { ckBTCTokenBase, createIcpUserToken, + createTokenWithBalance, createUserToken, } from "$tests/mocks/tokens-page.mock"; -import { TokenAmountV2 } from "@dfinity/utils"; describe("tokens-table.utils", () => { - const tokenWithBalance = ({ id, amount }: { id: number; amount: bigint }) => - createUserToken({ - universeId: principal(id), - balance: TokenAmountV2.fromUlps({ - amount, - token: { name: `T${id}`, symbol: `T${id}`, decimals: 8 }, - }), - }); const ckBTCToken = createUserToken({ universeId: CKBTC_UNIVERSE_CANISTER_ID, }); @@ -51,7 +42,7 @@ describe("tokens-table.utils", () => { describe("compareTokensByImportance", () => { it("should sort tokens by importance", () => { - const token0 = tokenWithBalance({ id: 0, amount: 0n }); + const token0 = createTokenWithBalance({ id: 0, amount: 0n }); const expectedOrder = [ckBTCToken, ckETHTToken, ckUSDCToken, token0]; expect( [token0, ckUSDCToken, ckETHTToken, ckBTCToken].sort( @@ -72,10 +63,16 @@ describe("tokens-table.utils", () => { }); describe("compareTokensWithBalanceOrImportedFirst", () => { - const token0 = tokenWithBalance({ id: 0, amount: 0n }); - const token1 = tokenWithBalance({ id: 1, amount: 1n }); - const importedTokenWithBalance = tokenWithBalance({ id: 2, amount: 1n }); - const importedTokenNoBalance = tokenWithBalance({ id: 3, amount: 0n }); + const token0 = createTokenWithBalance({ id: 0, amount: 0n }); + const token1 = createTokenWithBalance({ id: 1, amount: 1n }); + const importedTokenWithBalance = createTokenWithBalance({ + id: 2, + amount: 1n, + }); + const importedTokenNoBalance = createTokenWithBalance({ + id: 3, + amount: 0n, + }); const importedTokenIds = new Set([ importedTokenWithBalance.universeId.toText(), importedTokenNoBalance.universeId.toText(), diff --git a/frontend/src/tests/mocks/tokens-page.mock.ts b/frontend/src/tests/mocks/tokens-page.mock.ts index 3179260f21e..8a28de58d50 100644 --- a/frontend/src/tests/mocks/tokens-page.mock.ts +++ b/frontend/src/tests/mocks/tokens-page.mock.ts @@ -152,6 +152,25 @@ export const createUserToken = (params: Partial = {}) => { }; }; +export const createTokenWithBalance = ({ + id, + amount, +}: { + id: number; + amount: bigint; +}) => + createUserToken({ + universeId: principal(id), + balance: TokenAmountV2.fromUlps({ + amount, + token: { + name: `T${id}`, + symbol: `T${id}`, + decimals: 8, + }, + }), + }) as UserTokenData; + export const createIcpUserToken = (params: Partial = {}) => ({ ...icpTokenNoBalance, ...params, From 7b2714bc2dc0c13e40e0f641aae4e8c172782243 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Tue, 6 Aug 2024 15:48:55 +0200 Subject: [PATCH 109/166] test: should display imported tokens after important with balance --- .../src/tests/routes/app/tokens/page.spec.ts | 102 +++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/frontend/src/tests/routes/app/tokens/page.spec.ts b/frontend/src/tests/routes/app/tokens/page.spec.ts index dd30e39844f..335a1b03243 100644 --- a/frontend/src/tests/routes/app/tokens/page.spec.ts +++ b/frontend/src/tests/routes/app/tokens/page.spec.ts @@ -17,7 +17,10 @@ import { import { overrideFeatureFlagsStore } from "$lib/stores/feature-flags.store"; import { icrcAccountsStore } from "$lib/stores/icrc-accounts.store"; import { icrcCanistersStore } from "$lib/stores/icrc-canisters.store"; +import { importedTokensStore } from "$lib/stores/imported-tokens.store"; import { tokensStore } from "$lib/stores/tokens.store"; +import type { IcrcTokenMetadata } from "$lib/types/icrc"; +import type { ImportedTokenData } from "$lib/types/imported-tokens"; import { numberToUlps } from "$lib/utils/token.utils"; import TokensRoute from "$routes/(app)/(nns)/tokens/+page.svelte"; import { @@ -89,6 +92,20 @@ describe("Tokens route", () => { pending_utxos: [], required_confirmations: 0, }); + const ckToken1Id = principal(100); + const ckToken1Metadata = { + name: "ZTOKEN1", + symbol: "ZTOKEN1", + fee: 4_000n, + decimals: 6, + } as IcrcTokenMetadata; + const ckToken2Id = principal(101); + const ckToken2Metadata = { + name: "ATOKEN2", + symbol: "ATOKEN2", + fee: 4_000n, + decimals: 6, + } as IcrcTokenMetadata; const renderPage = async () => { const { container } = render(TokensRoute); @@ -115,6 +132,9 @@ describe("Tokens route", () => { [CKETH_UNIVERSE_CANISTER_ID.toText()]: mockCkETHToken, [CKETHSEPOLIA_UNIVERSE_CANISTER_ID.toText()]: mockCkTESTBTCToken, [CKUSDC_UNIVERSE_CANISTER_ID.toText()]: mockCkUSDCToken, + // imported tokens + [ckToken1Id.toText()]: ckToken1Metadata, + [ckToken2Id.toText()]: ckToken2Metadata, }; if (isNullish(tokenMap[canisterId.toText()])) { throw new Error( @@ -507,7 +527,7 @@ describe("Tokens route", () => { ]); }); - describe("taking balance into account", () => { + describe("taking balance and import tokens into account", () => { beforeEach(() => { vi.spyOn(icrcLedgerApi, "queryIcrcBalance").mockImplementation( async ({ canisterId }) => { @@ -545,6 +565,86 @@ describe("Tokens route", () => { }); }); + describe("imported tokens", () => { + const ckToken1Data: ImportedTokenData = { + ledgerCanisterId: ckToken1Id, + indexCanisterId: principal(111), + }; + const ckToken2Data: ImportedTokenData = { + ledgerCanisterId: ckToken2Id, + indexCanisterId: undefined, + }; + + beforeEach(() => { + importedTokensStore.reset(); + + vi.spyOn(icrcLedgerApi, "queryIcrcBalance").mockImplementation( + async ({ canisterId }) => { + const balancesMap = { + [CKBTC_UNIVERSE_CANISTER_ID.toText()]: ckBTCBalanceE8s, + [CKTESTBTC_UNIVERSE_CANISTER_ID.toText()]: ckBTCBalanceE8s, + [CKETH_UNIVERSE_CANISTER_ID.toText()]: 0n, + [CKUSDC_UNIVERSE_CANISTER_ID.toText()]: ckUSDCBalanceE8s, + [CKETHSEPOLIA_UNIVERSE_CANISTER_ID.toText()]: + ckETHBalanceUlps, + [ledgerCanisterIdTetris.toText()]: tetrisBalanceE8s, + [ledgerCanisterIdPacman.toText()]: 0n, + [ckToken1Id.toText()]: 10n, + [ckToken2Id.toText()]: 0n, + }; + if (isNullish(balancesMap[canisterId.toText()])) { + throw new Error( + `Account not found for canister ${canisterId.toText()}` + ); + } + return balancesMap[canisterId.toText()]; + } + ); + + // Add 2 imported tokens + tokensStore.setToken({ + canisterId: ckToken1Id, + token: ckToken1Metadata, + }); + icrcCanistersStore.setCanisters({ + ledgerCanisterId: ckToken1Id, + indexCanisterId: undefined, + }); + tokensStore.setToken({ + canisterId: ckToken2Id, + token: ckToken2Metadata, + }); + icrcCanistersStore.setCanisters({ + ledgerCanisterId: ckToken2Id, + indexCanisterId: undefined, + }); + + importedTokensStore.set({ + importedTokens: [ckToken1Data, ckToken2Data], + certified: true, + }); + }); + + it("should display imported tokens after important with balance", async () => { + const po = await renderPage(); + const tokensPagePo = po.getTokensPagePo(); + expect(await tokensPagePo.getTokenNames()).toEqual([ + "Internet Computer", + // ck with balance + "ckBTC", + "ckUSDC", + // Imported tokens should be placed with the SNS tokens that have a non-zero balance + // and should be sorted alphabetically. + "ATOKEN2", // Imported + "Tetris", // SNS with balance + "ZTOKEN1", // Imported + // Zero balance + "ckETH", + "Pacman", + ]); + }); + }); + describe("when logged out", () => { beforeEach(() => { setNoIdentity(); From f52928ffdd1a14068196215467e3d2f22b26ab06 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Tue, 6 Aug 2024 16:04:00 +0200 Subject: [PATCH 110/166] refactor: don't export createTokenWithBalance --- .../lib/utils/tokens-table.utils.spec.ts | 22 ++++++++++++++++++- frontend/src/tests/mocks/tokens-page.mock.ts | 19 ---------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts index 7ede83f1723..7b9c75c3fa9 100644 --- a/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts +++ b/frontend/src/tests/lib/utils/tokens-table.utils.spec.ts @@ -1,18 +1,20 @@ import { CKBTC_UNIVERSE_CANISTER_ID } from "$lib/constants/ckbtc-canister-ids.constants"; import { CKETH_UNIVERSE_CANISTER_ID } from "$lib/constants/cketh-canister-ids.constants"; import { CKUSDC_UNIVERSE_CANISTER_ID } from "$lib/constants/ckusdc-canister-ids.constants"; +import type { UserTokenData } from "$lib/types/tokens-page"; import { compareTokensAlphabetically, compareTokensByImportance, compareTokensIcpFirst, compareTokensWithBalanceOrImportedFirst, } from "$lib/utils/tokens-table.utils"; +import { principal } from "$tests/mocks/sns-projects.mock"; import { ckBTCTokenBase, createIcpUserToken, - createTokenWithBalance, createUserToken, } from "$tests/mocks/tokens-page.mock"; +import { TokenAmountV2 } from "@dfinity/utils"; describe("tokens-table.utils", () => { const ckBTCToken = createUserToken({ @@ -24,6 +26,24 @@ describe("tokens-table.utils", () => { const ckUSDCToken = createUserToken({ universeId: CKUSDC_UNIVERSE_CANISTER_ID, }); + const createTokenWithBalance = ({ + id, + amount, + }: { + id: number; + amount: bigint; + }) => + createUserToken({ + universeId: principal(id), + balance: TokenAmountV2.fromUlps({ + amount, + token: { + name: `T${id}`, + symbol: `T${id}`, + decimals: 8, + }, + }), + }) as UserTokenData; beforeEach(() => { vi.clearAllMocks(); diff --git a/frontend/src/tests/mocks/tokens-page.mock.ts b/frontend/src/tests/mocks/tokens-page.mock.ts index 8a28de58d50..3179260f21e 100644 --- a/frontend/src/tests/mocks/tokens-page.mock.ts +++ b/frontend/src/tests/mocks/tokens-page.mock.ts @@ -152,25 +152,6 @@ export const createUserToken = (params: Partial = {}) => { }; }; -export const createTokenWithBalance = ({ - id, - amount, -}: { - id: number; - amount: bigint; -}) => - createUserToken({ - universeId: principal(id), - balance: TokenAmountV2.fromUlps({ - amount, - token: { - name: `T${id}`, - symbol: `T${id}`, - decimals: 8, - }, - }), - }) as UserTokenData; - export const createIcpUserToken = (params: Partial = {}) => ({ ...icpTokenNoBalance, ...params, From 06e5be28c5b8725355ba31c0d9a227798d6c0a99 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 8 Aug 2024 15:51:33 +0200 Subject: [PATCH 111/166] Expose testId and require props for PrincipaInput component --- frontend/src/lib/components/ui/PrincipalInput.svelte | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/lib/components/ui/PrincipalInput.svelte b/frontend/src/lib/components/ui/PrincipalInput.svelte index baedf068c4b..9c224c1ddd6 100644 --- a/frontend/src/lib/components/ui/PrincipalInput.svelte +++ b/frontend/src/lib/components/ui/PrincipalInput.svelte @@ -7,6 +7,8 @@ export let placeholderLabelKey: string; export let name: string; export let principal: Principal | undefined = undefined; + export let required: boolean | undefined = undefined; + export let testId: string | undefined = undefined; let address = principal?.toText() ?? ""; $: principal = getPrincipalFromString(address); @@ -23,10 +25,12 @@ inputType="text" {placeholderLabelKey} {name} + {testId} bind:value={address} errorMessage={showError ? $i18n.error.principal_not_valid : undefined} on:blur={showErrorIfAny} showInfo={$$slots.label !== undefined} + {required} > From 37106ed2e8029e206e2bd77c47c1616fc8376bbe Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 8 Aug 2024 17:05:37 +0200 Subject: [PATCH 112/166] Update labels --- frontend/src/lib/i18n/en.json | 10 ++++++++++ frontend/src/lib/types/i18n.d.ts | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index 6641de6b8a6..96cbc5a3b8b 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -1043,5 +1043,15 @@ "import_token": "Import Token", "add_imported_token_success": "New token has been successfully imported!", "remove_imported_token_success": "The token has been successfully removed!" + }, + "import_token": { + "description": "To import a new token to your NNS dapp wallet, you will need to find, and paste the ledger canister id of the token. If you want to see your transaction history, you need to import the token’s index canister.", + "ledger_label": "Ledger Canister ID", + "index_label_optional": "Index Canister ID (Optional)", + "index_label": "Index Canister ID", + "placeholder": "00000-00000-00000-00000-000", + "index_canister_description": "Index Canister allows to display a token balance and transaction history. Note: not all tokens have index canisters.", + "review_token_info": "Review token info", + "warning": "Warning: Be careful what token you import! Anyone can create a token including one with the same name as existing tokens, such as ckBTC." } } diff --git a/frontend/src/lib/types/i18n.d.ts b/frontend/src/lib/types/i18n.d.ts index 64759a50e4c..5ab094ea91a 100644 --- a/frontend/src/lib/types/i18n.d.ts +++ b/frontend/src/lib/types/i18n.d.ts @@ -1105,6 +1105,17 @@ interface I18nTokens { remove_imported_token_success: string; } +interface I18nImport_token { + description: string; + ledger_label: string; + index_label_optional: string; + index_label: string; + placeholder: string; + index_canister_description: string; + review_token_info: string; + warning: string; +} + interface I18nNeuron_state { Unspecified: string; Locked: string; @@ -1389,6 +1400,7 @@ interface I18n { settings: I18nSettings; sync: I18nSync; tokens: I18nTokens; + import_token: I18nImport_token; neuron_state: I18nNeuron_state; topics: I18nTopics; topics_description: I18nTopics_description; From ac57c9cc0320800cdaf5d32e52fdd2174028ea7a Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 8 Aug 2024 17:06:00 +0200 Subject: [PATCH 113/166] New ImportTokenForm component --- .../accounts/ImportTokenForm.svelte | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 frontend/src/lib/components/accounts/ImportTokenForm.svelte diff --git a/frontend/src/lib/components/accounts/ImportTokenForm.svelte b/frontend/src/lib/components/accounts/ImportTokenForm.svelte new file mode 100644 index 00000000000..b2901a250e1 --- /dev/null +++ b/frontend/src/lib/components/accounts/ImportTokenForm.svelte @@ -0,0 +1,72 @@ + + + + {$i18n.import_token.description} + + dispatch("nnsSubmit")}> + + {$i18n.import_token.ledger_label} + + + + + + + + + + + + + + dispatch("nnsClose")} + > + {$i18n.core.cancel} + + + + {$i18n.core.next} + + + + + + From de7ed16044e3ef2c3ca1349171a366c13dc96954 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 8 Aug 2024 17:06:19 +0200 Subject: [PATCH 114/166] New ImportTokenModal component --- .../modals/accounts/ImportTokenModal.svelte | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 frontend/src/lib/modals/accounts/ImportTokenModal.svelte diff --git a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte new file mode 100644 index 00000000000..ae38debe4fa --- /dev/null +++ b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte @@ -0,0 +1,58 @@ + + + + {currentStep?.title} + + {#if currentStep?.name === STEP_FORM} + + {/if} + {#if currentStep?.name === STEP_REVIEW && nonNullish(ledgerCanisterId) && nonNullish(tokenMetaData)} + TBD: Review imported token + {/if} + From 245d9142130744b7cb444dc85543df1033d55944 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 8 Aug 2024 17:08:10 +0200 Subject: [PATCH 115/166] feat: show modal on "Import token" button click --- frontend/src/lib/pages/Tokens.svelte | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/src/lib/pages/Tokens.svelte b/frontend/src/lib/pages/Tokens.svelte index 6c11737f20d..dc553e9e3bc 100644 --- a/frontend/src/lib/pages/Tokens.svelte +++ b/frontend/src/lib/pages/Tokens.svelte @@ -11,6 +11,7 @@ import { Popover } from "@dfinity/gix-components"; import { TokenAmountV2 } from "@dfinity/utils"; import { ENABLE_IMPORT_TOKEN } from "$lib/stores/feature-flags.store"; + import ImportTokenModal from "$lib/modals/accounts/ImportTokenModal.svelte"; export let userTokensData: UserToken[]; @@ -41,9 +42,7 @@ hideZeroBalancesStore.set("show"); }; - const importToken = async () => { - // TBD: Implement import token. - }; + let showImportTokenModal = false; // TODO(Import token): After removing ENABLE_IMPORT_TOKEN combine divs -> @@ -82,7 +81,7 @@ (showImportTokenModal = true)} > {$i18n.tokens.import_token} @@ -112,6 +111,10 @@ > + + {#if showImportTokenModal} + (showImportTokenModal = false)} /> + {/if} From 6f092a4b56272ec5491d613a700fa3d20dd495a1 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Tue, 13 Aug 2024 11:34:56 +0200 Subject: [PATCH 133/166] reset package lock --- frontend/package-lock.json | 125 +++++++++++++++++-------------------- frontend/package.json | 6 +- 2 files changed, 60 insertions(+), 71 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f10f6c260d1..044e992ca74 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "@dfinity/nns-dapp", - "version": "2.0.85", + "version": "2.0.86", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@dfinity/nns-dapp", - "version": "2.0.85", + "version": "2.0.86", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@dfinity/agent": "^1.4.0", @@ -250,10 +250,9 @@ } }, "node_modules/@dfinity/ckbtc": { - "version": "2.5.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/ckbtc/-/ckbtc-2.5.0-next-2024-07-30.tgz", - "integrity": "sha512-Oj1hGhfv8kDP8Dq+QmPh3Gm6pHMJNnbYqNJ0pLHDyjnw7H+9XrHfFRvew+iPQ1YuyHQg+WjtuqY7Ph87TJCGFQ==", - "license": "Apache-2.0", + "version": "2.5.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/ckbtc/-/ckbtc-2.5.0-next-2024-08-10.tgz", + "integrity": "sha512-rAhnQ9i4lDHAOx+axm8m3NwqGLZFFa4BayDis+bEYp8ufkCgqDjF6v3BeJU3pN7dehUKpg97t8mA0rHGPYFE+A==", "dependencies": { "@noble/hashes": "^1.3.2", "base58-js": "^1.0.5", @@ -267,10 +266,9 @@ } }, "node_modules/@dfinity/cmc": { - "version": "3.1.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/cmc/-/cmc-3.1.0-next-2024-07-30.tgz", - "integrity": "sha512-d9TtZxI1fuQ0QzogMSTLfyy/WtCTahWgms0R9Htd85z3jZWVJ1+jH85MuG1kfPBQPsLH99izdcM96JlBTqv20w==", - "license": "Apache-2.0", + "version": "3.1.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/cmc/-/cmc-3.1.0-next-2024-08-10.tgz", + "integrity": "sha512-msb4dX0wmdfSaTIVred1NkfNOdLonwzQ83RVF1O/Y0U1q++NHFzMAsFc5hS4sig0hCcIgMw/HJ1ZXhNgweBfCw==", "peerDependencies": { "@dfinity/agent": "*", "@dfinity/candid": "*", @@ -279,9 +277,9 @@ } }, "node_modules/@dfinity/gix-components": { - "version": "4.6.0-next-2024-08-06", - "resolved": "https://registry.npmjs.org/@dfinity/gix-components/-/gix-components-4.6.0-next-2024-08-06.tgz", - "integrity": "sha512-oic5/+OqocCRoTBHIcsrrgrpBPDYYSytMcDyYtl1w7nW6ObOxoJig5IM9IBt8w0+J64S67rWnIA+UwQXUK1ufQ==", + "version": "4.6.0-next-2024-08-12", + "resolved": "https://registry.npmjs.org/@dfinity/gix-components/-/gix-components-4.6.0-next-2024-08-12.tgz", + "integrity": "sha512-KjVlUoADfuPKtl4YXfodMINXCmDTxpx5kjmddWwhDc2fxbdoiNdM5V2wkC3QzzYZgxC78QZY+AsMHr4F1JqZTg==", "license": "Apache-2.0", "dependencies": { "dompurify": "^3.1.6", @@ -294,10 +292,9 @@ } }, "node_modules/@dfinity/ic-management": { - "version": "5.1.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/ic-management/-/ic-management-5.1.0-next-2024-07-30.tgz", - "integrity": "sha512-FvjFqlOMpQ6x58sl9b/B9AEhZ+M8LwZK7Dxe2kKjzroBQ7yFVfuujkogICzk6p/xV6dlMuT/lVNTfFb2JEwd6g==", - "license": "Apache-2.0", + "version": "5.1.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/ic-management/-/ic-management-5.1.0-next-2024-08-10.tgz", + "integrity": "sha512-MVeiGQQTs2cKh1myzwEAZYK0ihyu8tFgToEqeUrP000830cRpkBpAmAde4GzmpeA9aRHatYUrvH1Mtu9L/Gr1A==", "peerDependencies": { "@dfinity/agent": "*", "@dfinity/candid": "*", @@ -321,10 +318,9 @@ } }, "node_modules/@dfinity/ledger-icp": { - "version": "2.4.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/ledger-icp/-/ledger-icp-2.4.0-next-2024-07-30.tgz", - "integrity": "sha512-pma0yUdZjyjD+L2lJEtt5YQ3U7OgQ/dGRfyNeECsrZxTXTwJbNR1QrqNzpJQ9pOGaLf7mKcMHb6dUxwdjV63Eg==", - "license": "Apache-2.0", + "version": "2.4.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/ledger-icp/-/ledger-icp-2.4.0-next-2024-08-10.tgz", + "integrity": "sha512-aVpUCrvH1/rZ1Us6d42czdSp40/sSXoi6I21lFajDXqOG4Cpqduos/4ICHyAd5rxcWz7DvzmHUGJMgl0FCvJGA==", "peerDependencies": { "@dfinity/agent": "*", "@dfinity/candid": "*", @@ -333,10 +329,9 @@ } }, "node_modules/@dfinity/ledger-icrc": { - "version": "2.4.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/ledger-icrc/-/ledger-icrc-2.4.0-next-2024-07-30.tgz", - "integrity": "sha512-CJnq4XquTa5eUlOV5eqMJhQWOA2ClUepm9ooTrxse18ka/6r/axb4JEpwK+1Ee7iyNJGa5Ij135bHdc2w2Qw1A==", - "license": "Apache-2.0", + "version": "2.4.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/ledger-icrc/-/ledger-icrc-2.4.0-next-2024-08-10.tgz", + "integrity": "sha512-jK/Xz8uCBBQ6QnQs0vJp17GO7q4VACMyOgvdvo4mDpdhAasEaceqOGeaghlU+E8nYqD9nH/ZPHKYa79Gai0j2g==", "peerDependencies": { "@dfinity/agent": "*", "@dfinity/candid": "*", @@ -345,10 +340,9 @@ } }, "node_modules/@dfinity/nns": { - "version": "5.2.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/nns/-/nns-5.2.0-next-2024-07-30.tgz", - "integrity": "sha512-VfaLTP15hFiZOh7moTKAgTzCMSMdYCZuP8v0piJ4qLkOIwdlhJMpobf97X2MedL5oaOkTISsU6rKyH5X+RwKmg==", - "license": "Apache-2.0", + "version": "5.2.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/nns/-/nns-5.2.0-next-2024-08-10.tgz", + "integrity": "sha512-WvD9OX9LzrOuExi8HPbGKUUZKkuy7i2rRSNUwcVHsN4pahio6HncTnKLLkgIQ2nf7iGHntCvTtJ00Xz3E6iKzg==", "dependencies": { "@noble/hashes": "^1.3.2", "randombytes": "^2.1.0" @@ -370,10 +364,9 @@ } }, "node_modules/@dfinity/sns": { - "version": "3.1.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/sns/-/sns-3.1.0-next-2024-07-30.tgz", - "integrity": "sha512-lG25m6F8capAVZTdSX07rq3OwbxoNNtaV+jwBrlxX2TO14u0bLrfJ5EiM101wIxfaomF8O/bNJSgrtyPB2Qemg==", - "license": "Apache-2.0", + "version": "3.1.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/sns/-/sns-3.1.0-next-2024-08-10.tgz", + "integrity": "sha512-D9B/+/IcKEz4TriOoh1q+k3VfWPt6FfwMjFMBlRGHcrOsgut8G5P0TUsK03dX50muLGLRpxwjWMAfF0sI04vjQ==", "dependencies": { "@noble/hashes": "^1.3.2" }, @@ -386,10 +379,9 @@ } }, "node_modules/@dfinity/utils": { - "version": "2.4.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/utils/-/utils-2.4.0-next-2024-07-30.tgz", - "integrity": "sha512-e+S6n4JX+ZtF1HzjG32tfVLWM2TMY0Xcbf0sRXmgx4S+DmKr8NA705dq4MmCike/W4RhT2jEljoNIixZwhkV1g==", - "license": "Apache-2.0", + "version": "2.4.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/utils/-/utils-2.4.0-next-2024-08-10.tgz", + "integrity": "sha512-17YrSzkw1E5pIq/yUYKraItdpXhu9XIS5+CX52a8xkChQYkKR4wpQu1r6a9wW53NZq+LOsa+lAl/clJAzTJi7g==", "peerDependencies": { "@dfinity/agent": "*", "@dfinity/candid": "*", @@ -2030,7 +2022,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/base58-js/-/base58-js-1.0.5.tgz", "integrity": "sha512-LkkAPP8Zu+c0SVNRTRVDyMfKVORThX+rCViget00xdgLRrKkClCTz1T7cIrpr69ShwV5XJuuoZvMvJ43yURwkA==", - "license": "MIT", "engines": { "node": ">= 8" } @@ -2065,8 +2056,7 @@ "node_modules/bech32": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", - "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==", - "license": "MIT" + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" }, "node_modules/bignumber.js": { "version": "9.1.1", @@ -5389,7 +5379,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -7044,9 +7033,9 @@ "requires": {} }, "@dfinity/ckbtc": { - "version": "2.5.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/ckbtc/-/ckbtc-2.5.0-next-2024-07-30.tgz", - "integrity": "sha512-Oj1hGhfv8kDP8Dq+QmPh3Gm6pHMJNnbYqNJ0pLHDyjnw7H+9XrHfFRvew+iPQ1YuyHQg+WjtuqY7Ph87TJCGFQ==", + "version": "2.5.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/ckbtc/-/ckbtc-2.5.0-next-2024-08-10.tgz", + "integrity": "sha512-rAhnQ9i4lDHAOx+axm8m3NwqGLZFFa4BayDis+bEYp8ufkCgqDjF6v3BeJU3pN7dehUKpg97t8mA0rHGPYFE+A==", "requires": { "@noble/hashes": "^1.3.2", "base58-js": "^1.0.5", @@ -7054,15 +7043,15 @@ } }, "@dfinity/cmc": { - "version": "3.1.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/cmc/-/cmc-3.1.0-next-2024-07-30.tgz", - "integrity": "sha512-d9TtZxI1fuQ0QzogMSTLfyy/WtCTahWgms0R9Htd85z3jZWVJ1+jH85MuG1kfPBQPsLH99izdcM96JlBTqv20w==", + "version": "3.1.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/cmc/-/cmc-3.1.0-next-2024-08-10.tgz", + "integrity": "sha512-msb4dX0wmdfSaTIVred1NkfNOdLonwzQ83RVF1O/Y0U1q++NHFzMAsFc5hS4sig0hCcIgMw/HJ1ZXhNgweBfCw==", "requires": {} }, "@dfinity/gix-components": { - "version": "4.6.0-next-2024-08-06", - "resolved": "https://registry.npmjs.org/@dfinity/gix-components/-/gix-components-4.6.0-next-2024-08-06.tgz", - "integrity": "sha512-oic5/+OqocCRoTBHIcsrrgrpBPDYYSytMcDyYtl1w7nW6ObOxoJig5IM9IBt8w0+J64S67rWnIA+UwQXUK1ufQ==", + "version": "4.6.0-next-2024-08-12", + "resolved": "https://registry.npmjs.org/@dfinity/gix-components/-/gix-components-4.6.0-next-2024-08-12.tgz", + "integrity": "sha512-KjVlUoADfuPKtl4YXfodMINXCmDTxpx5kjmddWwhDc2fxbdoiNdM5V2wkC3QzzYZgxC78QZY+AsMHr4F1JqZTg==", "requires": { "dompurify": "^3.1.6", "html5-qrcode": "^2.3.8", @@ -7070,9 +7059,9 @@ } }, "@dfinity/ic-management": { - "version": "5.1.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/ic-management/-/ic-management-5.1.0-next-2024-07-30.tgz", - "integrity": "sha512-FvjFqlOMpQ6x58sl9b/B9AEhZ+M8LwZK7Dxe2kKjzroBQ7yFVfuujkogICzk6p/xV6dlMuT/lVNTfFb2JEwd6g==", + "version": "5.1.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/ic-management/-/ic-management-5.1.0-next-2024-08-10.tgz", + "integrity": "sha512-MVeiGQQTs2cKh1myzwEAZYK0ihyu8tFgToEqeUrP000830cRpkBpAmAde4GzmpeA9aRHatYUrvH1Mtu9L/Gr1A==", "requires": {} }, "@dfinity/identity": { @@ -7086,21 +7075,21 @@ } }, "@dfinity/ledger-icp": { - "version": "2.4.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/ledger-icp/-/ledger-icp-2.4.0-next-2024-07-30.tgz", - "integrity": "sha512-pma0yUdZjyjD+L2lJEtt5YQ3U7OgQ/dGRfyNeECsrZxTXTwJbNR1QrqNzpJQ9pOGaLf7mKcMHb6dUxwdjV63Eg==", + "version": "2.4.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/ledger-icp/-/ledger-icp-2.4.0-next-2024-08-10.tgz", + "integrity": "sha512-aVpUCrvH1/rZ1Us6d42czdSp40/sSXoi6I21lFajDXqOG4Cpqduos/4ICHyAd5rxcWz7DvzmHUGJMgl0FCvJGA==", "requires": {} }, "@dfinity/ledger-icrc": { - "version": "2.4.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/ledger-icrc/-/ledger-icrc-2.4.0-next-2024-07-30.tgz", - "integrity": "sha512-CJnq4XquTa5eUlOV5eqMJhQWOA2ClUepm9ooTrxse18ka/6r/axb4JEpwK+1Ee7iyNJGa5Ij135bHdc2w2Qw1A==", + "version": "2.4.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/ledger-icrc/-/ledger-icrc-2.4.0-next-2024-08-10.tgz", + "integrity": "sha512-jK/Xz8uCBBQ6QnQs0vJp17GO7q4VACMyOgvdvo4mDpdhAasEaceqOGeaghlU+E8nYqD9nH/ZPHKYa79Gai0j2g==", "requires": {} }, "@dfinity/nns": { - "version": "5.2.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/nns/-/nns-5.2.0-next-2024-07-30.tgz", - "integrity": "sha512-VfaLTP15hFiZOh7moTKAgTzCMSMdYCZuP8v0piJ4qLkOIwdlhJMpobf97X2MedL5oaOkTISsU6rKyH5X+RwKmg==", + "version": "5.2.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/nns/-/nns-5.2.0-next-2024-08-10.tgz", + "integrity": "sha512-WvD9OX9LzrOuExi8HPbGKUUZKkuy7i2rRSNUwcVHsN4pahio6HncTnKLLkgIQ2nf7iGHntCvTtJ00Xz3E6iKzg==", "requires": { "@noble/hashes": "^1.3.2", "randombytes": "^2.1.0" @@ -7115,17 +7104,17 @@ } }, "@dfinity/sns": { - "version": "3.1.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/sns/-/sns-3.1.0-next-2024-07-30.tgz", - "integrity": "sha512-lG25m6F8capAVZTdSX07rq3OwbxoNNtaV+jwBrlxX2TO14u0bLrfJ5EiM101wIxfaomF8O/bNJSgrtyPB2Qemg==", + "version": "3.1.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/sns/-/sns-3.1.0-next-2024-08-10.tgz", + "integrity": "sha512-D9B/+/IcKEz4TriOoh1q+k3VfWPt6FfwMjFMBlRGHcrOsgut8G5P0TUsK03dX50muLGLRpxwjWMAfF0sI04vjQ==", "requires": { "@noble/hashes": "^1.3.2" } }, "@dfinity/utils": { - "version": "2.4.0-next-2024-07-30", - "resolved": "https://registry.npmjs.org/@dfinity/utils/-/utils-2.4.0-next-2024-07-30.tgz", - "integrity": "sha512-e+S6n4JX+ZtF1HzjG32tfVLWM2TMY0Xcbf0sRXmgx4S+DmKr8NA705dq4MmCike/W4RhT2jEljoNIixZwhkV1g==", + "version": "2.4.0-next-2024-08-10", + "resolved": "https://registry.npmjs.org/@dfinity/utils/-/utils-2.4.0-next-2024-08-10.tgz", + "integrity": "sha512-17YrSzkw1E5pIq/yUYKraItdpXhu9XIS5+CX52a8xkChQYkKR4wpQu1r6a9wW53NZq+LOsa+lAl/clJAzTJi7g==", "requires": {} }, "@esbuild/android-arm": { diff --git a/frontend/package.json b/frontend/package.json index cdd248c2b86..92eb55878b4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "@dfinity/nns-dapp", - "version": "2.0.85", + "version": "2.0.86", "private": true, "license": "SEE LICENSE IN LICENSE.md", "scripts": { @@ -67,11 +67,11 @@ "@dfinity/candid": "^1.3.0", "@dfinity/ckbtc": "next", "@dfinity/cmc": "next", - "@dfinity/gix-components": "file:../../gix-components", + "@dfinity/gix-components": "next", "@dfinity/ic-management": "next", "@dfinity/identity": "^1.3.0", "@dfinity/ledger-icp": "next", - "@dfinity/ledger-icrc": "file:../../ic-js/packages/ledger-icrc", + "@dfinity/ledger-icrc": "next", "@dfinity/nns": "next", "@dfinity/principal": "^1.3.0", "@dfinity/sns": "next", From 75cfd531d780f3e484852a64d8ddeec7ae0f5b2c Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Tue, 13 Aug 2024 11:52:37 +0200 Subject: [PATCH 134/166] cleanup --- .../src/lib/components/universe/UniversePageSummary.svelte | 4 ---- 1 file changed, 4 deletions(-) diff --git a/frontend/src/lib/components/universe/UniversePageSummary.svelte b/frontend/src/lib/components/universe/UniversePageSummary.svelte index b7545d237f1..f6c91fab03f 100644 --- a/frontend/src/lib/components/universe/UniversePageSummary.svelte +++ b/frontend/src/lib/components/universe/UniversePageSummary.svelte @@ -39,8 +39,4 @@ @include fonts.h3; @include text.truncate; } - - .remove { - color: var(--negative-emphasis); - } From 3e5f876dfa4c44aa26be325ff3c032fcc779a2d6 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Tue, 13 Aug 2024 12:07:05 +0200 Subject: [PATCH 135/166] cleanup --- frontend/src/lib/api/icrc-index.api.ts | 4 ++-- frontend/src/lib/modals/accounts/ImportTokenModal.svelte | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/lib/api/icrc-index.api.ts b/frontend/src/lib/api/icrc-index.api.ts index ce24afc618f..1df05afa861 100644 --- a/frontend/src/lib/api/icrc-index.api.ts +++ b/frontend/src/lib/api/icrc-index.api.ts @@ -55,10 +55,10 @@ export const getLedgerId = async ({ certified?: boolean; }): Promise => { const { - canister: { getLedgerId }, + canister: { ledgerId }, } = await indexCanister({ identity, canisterId: indexCanisterId }); - return getLedgerId({ certified }); + return ledgerId({ certified }); }; const indexCanister = async ({ diff --git a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte index ac4d88c6c21..06a950e4615 100644 --- a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte +++ b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte @@ -11,7 +11,6 @@ import { isNullish, nonNullish } from "@dfinity/utils"; import ImportTokenReview from "$lib/components/accounts/ImportTokenReview.svelte"; import { startBusy, stopBusy } from "$lib/stores/busy.store"; - import { fetchIcrcTokenMetaData } from "$lib/services/icrc-accounts.services"; import { toastsError } from "$lib/stores/toasts.store"; import { importedTokensStore } from "$lib/stores/imported-tokens.store"; import { addImportedToken } from "$lib/services/imported-tokens.services"; @@ -19,6 +18,7 @@ import { goto } from "$app/navigation"; import { createEventDispatcher } from "svelte"; import { validateLedgerIndexPair } from "$lib/services/icrc-index.services"; + import { getIcrcTokenMetaData } from "$lib/services/icrc-accounts.services"; let currentStep: WizardStep | undefined = undefined; const dispatch = createEventDispatcher(); @@ -52,7 +52,7 @@ if (isNullish(ledgerCanisterId)) { return; } - const meta = await fetchIcrcTokenMetaData({ ledgerCanisterId }); + const meta = await getIcrcTokenMetaData({ ledgerCanisterId }); if (isNullish(meta)) { tokenMetaData = undefined; toastsError({ From ffb6bfa67354e07ceef528e5bdf7d3648641bfcf Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 14 Aug 2024 11:31:11 +0200 Subject: [PATCH 136/166] New const IMPORTANT_CK_TOKEN_IDS --- .../constants/important-ck-tokens.constants.ts | 15 +++++++++++++++ frontend/src/lib/utils/tokens-table.utils.ts | 12 ++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 frontend/src/lib/constants/important-ck-tokens.constants.ts diff --git a/frontend/src/lib/constants/important-ck-tokens.constants.ts b/frontend/src/lib/constants/important-ck-tokens.constants.ts new file mode 100644 index 00000000000..edb860f65f3 --- /dev/null +++ b/frontend/src/lib/constants/important-ck-tokens.constants.ts @@ -0,0 +1,15 @@ +import { + CKBTC_UNIVERSE_CANISTER_ID, + CKTESTBTC_UNIVERSE_CANISTER_ID, +} from "$lib/constants/ckbtc-canister-ids.constants"; +import { CKETH_UNIVERSE_CANISTER_ID } from "$lib/constants/cketh-canister-ids.constants"; +import { CKUSDC_UNIVERSE_CANISTER_ID } from "$lib/constants/ckusdc-canister-ids.constants"; + +// Tokens that have significance within the Internet Computer ecosystem. +// The fixed order maps to a descending order in the market cap of the underlying native tokens. +export const IMPORTANT_CK_TOKEN_IDS = [ + CKBTC_UNIVERSE_CANISTER_ID, + CKTESTBTC_UNIVERSE_CANISTER_ID, + CKETH_UNIVERSE_CANISTER_ID, + CKUSDC_UNIVERSE_CANISTER_ID, +]; diff --git a/frontend/src/lib/utils/tokens-table.utils.ts b/frontend/src/lib/utils/tokens-table.utils.ts index ce809e79fec..338ca03bdc0 100644 --- a/frontend/src/lib/utils/tokens-table.utils.ts +++ b/frontend/src/lib/utils/tokens-table.utils.ts @@ -1,7 +1,5 @@ import { OWN_CANISTER_ID_TEXT } from "$lib/constants/canister-ids.constants"; -import { CKBTC_UNIVERSE_CANISTER_ID } from "$lib/constants/ckbtc-canister-ids.constants"; -import { CKETH_UNIVERSE_CANISTER_ID } from "$lib/constants/cketh-canister-ids.constants"; -import { CKUSDC_UNIVERSE_CANISTER_ID } from "$lib/constants/ckusdc-canister-ids.constants"; +import { IMPORTANT_CK_TOKEN_IDS } from "$lib/constants/important-ck-tokens.constants"; import type { UserToken } from "$lib/types/tokens-page"; import { createAscendingComparator, @@ -31,11 +29,9 @@ export const compareTokensWithBalanceOrImportedFirst = ({ // These tokens should be placed before others (but after ICP) // because they have significance within the Internet Computer ecosystem and deserve to be highlighted. // Where the fixed order maps to a descending order in the market cap of the underlying native tokens. -const ImportantCkTokenIds = [ - CKBTC_UNIVERSE_CANISTER_ID.toText(), - CKETH_UNIVERSE_CANISTER_ID.toText(), - CKUSDC_UNIVERSE_CANISTER_ID.toText(), -] +const ImportantCkTokenIds = IMPORTANT_CK_TOKEN_IDS.map((token) => + token.toText() +) // To place other tokens (which get an index of -1) at the bottom. .reverse(); export const compareTokensByImportance = createDescendingComparator( From 9ce3fe6d37426fe5cfe9028507e922f11771a9c5 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 14 Aug 2024 14:59:53 +0200 Subject: [PATCH 137/166] Import token validation before review --- frontend/src/lib/i18n/en.json | 5 +- .../modals/accounts/ImportTokenModal.svelte | 75 +++++++++++++++---- .../lib/services/icrc-accounts.services.ts | 2 +- .../src/lib/services/icrc-index.services.ts | 2 +- frontend/src/lib/types/i18n.d.ts | 3 + .../src/lib/utils/imported-tokens.utils.ts | 22 ++++++ frontend/src/lib/utils/sns.utils.ts | 16 ++++ 7 files changed, 107 insertions(+), 18 deletions(-) diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index 54dc8b5dcf7..48afec32a8b 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -845,7 +845,10 @@ "load_imported_tokens": "There was an unexpected issue while loading imported tokens.", "add_imported_token": "There was an unexpected issue while adding new imported token.", "remove_imported_token": "There was an unexpected issue while removing the imported token.", - "too_many": "You can't import more than $limit tokens." + "too_many": "You can't import more than $limit tokens.", + "is_duplication": "You have already imported this token, you can find it in the token list.", + "is_sns": "You cannot import SNS tokens, they are added automatically.", + "is_important": "This token is already in the token list." }, "error__sns": { "undefined_project": "The requested project is invalid or throws an error.", diff --git a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte index 06a950e4615..66154f6e375 100644 --- a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte +++ b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte @@ -17,8 +17,14 @@ import { buildWalletUrl } from "$lib/utils/navigation.utils"; import { goto } from "$app/navigation"; import { createEventDispatcher } from "svelte"; - import { validateLedgerIndexPair } from "$lib/services/icrc-index.services"; + import { matchLedgerIndexPair } from "$lib/services/icrc-index.services"; import { getIcrcTokenMetaData } from "$lib/services/icrc-accounts.services"; + import { + isImportantCkToken, + isUniqueImportedToken, + } from "$lib/utils/imported-tokens.utils"; + import { snsProjectsCommittedStore } from "$lib/derived/sns/sns-projects.derived"; + import { isSnsLedgerCanisterId } from "$lib/utils/sns.utils"; let currentStep: WizardStep | undefined = undefined; const dispatch = createEventDispatcher(); @@ -48,39 +54,78 @@ let indexCanisterId: Principal | undefined; let tokenMetaData: IcrcTokenMetadata | undefined; - const getTokenMetaData = async (): Promise => { - if (isNullish(ledgerCanisterId)) { - return; - } - const meta = await getIcrcTokenMetaData({ ledgerCanisterId }); - if (isNullish(meta)) { - tokenMetaData = undefined; + const getTokenMetaData = async ( + ledgerCanisterId: Principal + ): Promise => { + try { + return await getIcrcTokenMetaData({ ledgerCanisterId }); + } catch (err) { toastsError({ labelKey: "import_token.ledger_canister_loading_error", + err, }); - return; } - return meta; }; + const onUserInput = async () => { if (isNullish(ledgerCanisterId)) return; + // Ledger canister ID validation + if ( + !isUniqueImportedToken({ + ledgerCanisterId, + importedTokens: $importedTokensStore?.importedTokens, + }) + ) { + return toastsError({ + labelKey: "error__imported_tokens.is_duplication", + }); + } + if ( + isSnsLedgerCanisterId({ + ledgerCanisterId, + snsProjects: $snsProjectsCommittedStore, + }) + ) { + return toastsError({ + labelKey: "error__imported_tokens.is_sns", + }); + } + if ( + isImportantCkToken({ + ledgerCanisterId, + }) + ) { + return toastsError({ + labelKey: "error__imported_tokens.is_important", + }); + } + startBusy({ initiator: "import-token-validation", labelKey: "import_token.verifying", }); - tokenMetaData = await getTokenMetaData(); + + tokenMetaData = await getTokenMetaData(ledgerCanisterId); + // No need to validate index canister if tokenMetaData fails to load or no index canister is provided const validOrEmptyIndexCanister = - nonNullish(tokenMetaData) && nonNullish(indexCanisterId) - ? await validateLedgerIndexPair({ ledgerCanisterId, indexCanisterId }) - : true; + nonNullish(tokenMetaData) && + (nonNullish(indexCanisterId) + ? await matchLedgerIndexPair({ ledgerCanisterId, indexCanisterId }) + : true); + console.log( + "validOrEmptyIndexCanister", + validOrEmptyIndexCanister, + tokenMetaData + ); stopBusy("import-token-validation"); - if (nonNullish(tokenMetaData) && validOrEmptyIndexCanister) { + if (validOrEmptyIndexCanister) { next(); } }; + const onUserConfirm = async () => { if ( isNullish(ledgerCanisterId) || diff --git a/frontend/src/lib/services/icrc-accounts.services.ts b/frontend/src/lib/services/icrc-accounts.services.ts index a03066e5ca1..e67acfc6285 100644 --- a/frontend/src/lib/services/icrc-accounts.services.ts +++ b/frontend/src/lib/services/icrc-accounts.services.ts @@ -40,7 +40,7 @@ export const getIcrcTokenMetaData = async ({ ledgerCanisterId, }: { ledgerCanisterId: Principal; -}): Promise => { +}): Promise => { return queryIcrcToken({ identity: getCurrentIdentity(), canisterId: ledgerCanisterId, diff --git a/frontend/src/lib/services/icrc-index.services.ts b/frontend/src/lib/services/icrc-index.services.ts index 12ac29f109c..7ac10df3014 100644 --- a/frontend/src/lib/services/icrc-index.services.ts +++ b/frontend/src/lib/services/icrc-index.services.ts @@ -24,7 +24,7 @@ const getLedgerId = async ({ * This function uses `ledger_id` icrc1 index canister api to check if the indexCanisterId is correctly associated with * the provided ledgerCanisterId. */ -export const validateLedgerIndexPair = async ({ +export const matchLedgerIndexPair = async ({ ledgerCanisterId, indexCanisterId, }: { diff --git a/frontend/src/lib/types/i18n.d.ts b/frontend/src/lib/types/i18n.d.ts index 9e02a1eb394..134ad8d2b5c 100644 --- a/frontend/src/lib/types/i18n.d.ts +++ b/frontend/src/lib/types/i18n.d.ts @@ -884,6 +884,9 @@ interface I18nError__imported_tokens { add_imported_token: string; remove_imported_token: string; too_many: string; + is_duplication: string; + is_sns: string; + is_important: string; } interface I18nError__sns { diff --git a/frontend/src/lib/utils/imported-tokens.utils.ts b/frontend/src/lib/utils/imported-tokens.utils.ts index 62c112f861d..c434dde9027 100644 --- a/frontend/src/lib/utils/imported-tokens.utils.ts +++ b/frontend/src/lib/utils/imported-tokens.utils.ts @@ -1,4 +1,5 @@ import type { ImportedToken } from "$lib/canisters/nns-dapp/nns-dapp.types"; +import { IMPORTANT_CK_TOKEN_IDS } from "$lib/constants/important-ck-tokens.constants"; import type { ImportedTokenData } from "$lib/types/imported-tokens"; import type { Principal } from "@dfinity/principal"; import { fromNullable, nonNullish, toNullable } from "@dfinity/utils"; @@ -32,3 +33,24 @@ export const isImportedToken = ({ importedTokens.some( ({ ledgerCanisterId: id }) => id.toText() === ledgerCanisterId.toText() ); + +export const isUniqueImportedToken = ({ + ledgerCanisterId, + importedTokens, +}: { + ledgerCanisterId: Principal; + importedTokens: ImportedTokenData[] | undefined; +}): boolean => + nonNullish(importedTokens) && + importedTokens.every( + ({ ledgerCanisterId: id }) => id.toText() !== ledgerCanisterId.toText() + ); + +export const isImportantCkToken = ({ + ledgerCanisterId, +}: { + ledgerCanisterId: Principal; +}): boolean => + IMPORTANT_CK_TOKEN_IDS.some( + (token) => token.toText() === ledgerCanisterId.toText() + ); diff --git a/frontend/src/lib/utils/sns.utils.ts b/frontend/src/lib/utils/sns.utils.ts index 3d4404f318c..54d8b5b4fe7 100644 --- a/frontend/src/lib/utils/sns.utils.ts +++ b/frontend/src/lib/utils/sns.utils.ts @@ -1,5 +1,6 @@ import { SECONDS_IN_DAY } from "$lib/constants/constants"; import { MIN_VALID_SNS_GENERIC_NERVOUS_SYSTEM_FUNCTION_ID } from "$lib/constants/sns-proposals.constants"; +import type { SnsFullProject } from "$lib/derived/sns/sns-projects.derived"; import type { SnsTicketsStoreData } from "$lib/stores/sns-tickets.store"; import type { TicketStatus } from "$lib/types/sale"; import type { SnsSwapCommitment } from "$lib/types/sns"; @@ -202,3 +203,18 @@ export const isSnsGenericNervousSystemTypeProposal = ({ action, }: SnsProposalData): boolean => action >= MIN_VALID_SNS_GENERIC_NERVOUS_SYSTEM_FUNCTION_ID; + +/** + * Returns true if the ledgerId is one of the SNS projects. + */ +export const isSnsLedgerCanisterId = ({ + ledgerCanisterId, + snsProjects, +}: { + ledgerCanisterId: Principal; + snsProjects: SnsFullProject[]; +}): boolean => + snsProjects.some( + ({ summary }) => + summary.ledgerCanisterId.toText() === ledgerCanisterId.toText() + ); From ad478a6f8c6c4efdd905a228c19c860c8a919d70 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 14 Aug 2024 15:00:16 +0200 Subject: [PATCH 138/166] Do not show import buttons before the imported tokens are loaded --- frontend/src/lib/pages/Tokens.svelte | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/frontend/src/lib/pages/Tokens.svelte b/frontend/src/lib/pages/Tokens.svelte index 92e3c231ca5..be95df9adb4 100644 --- a/frontend/src/lib/pages/Tokens.svelte +++ b/frontend/src/lib/pages/Tokens.svelte @@ -9,9 +9,10 @@ import { heightTransition } from "$lib/utils/transition.utils"; import { IconPlus, IconSettings } from "@dfinity/gix-components"; import { Popover } from "@dfinity/gix-components"; - import { TokenAmountV2 } from "@dfinity/utils"; + import { nonNullish, TokenAmountV2 } from "@dfinity/utils"; import { ENABLE_IMPORT_TOKEN } from "$lib/stores/feature-flags.store"; import ImportTokenModal from "$lib/modals/accounts/ImportTokenModal.svelte"; + import { importedTokensStore } from "$lib/stores/imported-tokens.store"; export let userTokensData: UserToken[]; @@ -42,6 +43,9 @@ hideZeroBalancesStore.set("show"); }; + let shownImportTokenButton = false; + $: shownImportTokenButton = nonNullish($importedTokensStore.importedTokens); + let showImportTokenModal = false; // TODO(Import token): After removing ENABLE_IMPORT_TOKEN combine divs -> @@ -78,13 +82,15 @@ {/if} - (showImportTokenModal = true)} - > - {$i18n.import_token.import_token} - + {#if shownImportTokenButton} + (showImportTokenModal = true)} + > + {$i18n.import_token.import_token} + + {/if} {:else if shouldHideZeroBalances} Date: Wed, 14 Aug 2024 15:02:38 +0200 Subject: [PATCH 139/166] Squashed commit of the following: commit af47a6f888a222712b086122a58f0cc818606467 Author: Max Strasinsky Date: Wed Aug 14 10:00:56 2024 +0200 cleanup: remove redundant wrapper commit 5343c8a75f32f7680404d6060b49479ea37b7d4e Author: Max Strasinsky Date: Fri Aug 2 14:55:09 2024 +0200 Update test environment warning. commit 49f95bee04266cc4ba600794116a62923ffd1245 Author: sa-github-api <138766536+sa-github-api@users.noreply.github.com> Date: Tue Aug 13 18:01:12 2024 +0200 bot: Bump ic-js (#5315) # Motivation We want to pull in the latest changes. # Changes * Ran `npm run upgrade:next` # Tests * CI should pass * The pulled in changes should have been tested before being committed to their repositories. Co-authored-by: gix-bot --- .../warnings/TestEnvironmentWarning.svelte | 12 +++++------- frontend/src/lib/i18n/en.json | 4 +--- frontend/src/lib/types/i18n.d.ts | 4 +--- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/frontend/src/lib/components/warnings/TestEnvironmentWarning.svelte b/frontend/src/lib/components/warnings/TestEnvironmentWarning.svelte index 524633de7d0..c02799c4af8 100644 --- a/frontend/src/lib/components/warnings/TestEnvironmentWarning.svelte +++ b/frontend/src/lib/components/warnings/TestEnvironmentWarning.svelte @@ -24,18 +24,12 @@ {$i18n.warning.test_env_title} - {$i18n.warning.test_env_welcome} - - - {$i18n.warning.test_env_request} - - - {$i18n.warning.test_env_confirm} @@ -53,4 +47,8 @@ justify-content: center; padding: var(--padding-2x) 0 var(--padding); } + + p { + padding: 0 var(--padding); + } diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index 48afec32a8b..b1667df19b2 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -126,9 +126,7 @@ }, "warning": { "auth_sign_out": "You have been logged out because your session has expired.", - "test_env_welcome": "Welcome to the Testing Environment.", - "test_env_note": "Please note that you are currently using a test version of NNS-dapp that operates on the Internet Computer mainnet. Although it utilizes real data, it is intended solely for testing purposes.", - "test_env_request": "We kindly remind you that the functionality and availability of this testing dapp may change or even disappear at any time. Therefore, it is crucial to refrain from relying on it for any production or critical activities.", + "test_env_note": "Use with caution! This is not stable software, and it is not securely updated by the Network Nervous System. However, it accesses your real wallets and neurons. Functionality you see here can change at any time, and this dapp may not always be available.", "test_env_confirm": "I understand and want to continue", "test_env_title": "Warning" }, diff --git a/frontend/src/lib/types/i18n.d.ts b/frontend/src/lib/types/i18n.d.ts index 134ad8d2b5c..5813570b0c3 100644 --- a/frontend/src/lib/types/i18n.d.ts +++ b/frontend/src/lib/types/i18n.d.ts @@ -131,9 +131,7 @@ interface I18nError { interface I18nWarning { auth_sign_out: string; - test_env_welcome: string; test_env_note: string; - test_env_request: string; test_env_confirm: string; test_env_title: string; } @@ -179,8 +177,8 @@ interface I18nAccounts { add_account: string; new_account_title: string; new_linked_subtitle: string; - attach_hardware_title: string; attach_hardware_subtitle: string; + attach_hardware_title: string; attach_hardware_name_placeholder: string; attach_hardware_enter_name: string; attach_hardware_description: string; From 4af138aba8b91b886a91ec3306dcdb7d1970798a Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 14 Aug 2024 15:14:35 +0200 Subject: [PATCH 140/166] Squashed commit of the following: commit 25daef42663924fa9ecc784f33326c8ef3145bc4 Author: Max Strasinsky Date: Tue Aug 13 10:02:03 2024 +0200 Use link to icp ledger canister commit 7ab3b0cf6b192d79dcdc17cb6f99f5fcbae4a437 Author: Max Strasinsky Date: Tue Aug 13 10:01:26 2024 +0200 refactor: get rid of the "more-popup-content" tid commit 1a8d43ca9506390563e79d3df6dbae47e403037a Author: Max Strasinsky Date: Tue Aug 13 09:41:44 2024 +0200 Remove noLabel prop commit d3d32623ecee1289852d51235e2c630d2661e1c7 Author: Max Strasinsky Date: Mon Aug 12 17:40:28 2024 +0200 Comments commit b65f790de7273c08caf4e7461ac6889200eb8a25 Author: Max Strasinsky Date: Mon Aug 12 17:20:26 2024 +0200 test: should display more popup on NnsWallet page commit 82dc8284925d02b3a9a73d0a77d7faff4d38d721 Author: Max Strasinsky Date: Mon Aug 12 16:58:33 2024 +0200 test: LinkToDashboardCanister commit 3b598926f8076ab688e7dbdcad428e9dc0e3e6c3 Author: Max Strasinsky Date: Mon Aug 12 16:27:00 2024 +0200 Display popup on Nns wallet page commit c04b7b520e319a156e5ea1c11ff0bedac4680772 Author: Max Strasinsky Date: Mon Aug 12 16:25:42 2024 +0200 Add "actions" slot to the UniversePageSummary commit 8bbbb3aeb9e76d51ba929a584da998f543e06cbf Author: Max Strasinsky Date: Mon Aug 12 16:22:31 2024 +0200 New LinkToDashboardCanister component --- .../components/accounts/IcrcWalletPage.svelte | 14 +++++++- .../accounts/WalletPageHeader.svelte | 1 + .../tokens/LinkToDashboardCanister.svelte | 27 ++++++++++++++++ .../universe/UniversePageSummary.svelte | 16 +--------- frontend/src/lib/i18n/en.json | 1 - frontend/src/lib/pages/NnsWallet.svelte | 6 ++-- frontend/src/lib/types/i18n.d.ts | 3 +- .../tokens/LinkToDashboardCanister.spec.ts | 32 +++++++++++++++++++ .../src/tests/lib/pages/NnsWallet.spec.ts | 23 +++++++++++++ .../LinkToDashboardCanister.page-object.ts | 24 ++++++++++++++ .../page-objects/NnsWallet.page-object.ts | 13 ++++++++ 11 files changed, 137 insertions(+), 23 deletions(-) create mode 100644 frontend/src/lib/components/tokens/LinkToDashboardCanister.svelte create mode 100644 frontend/src/tests/lib/components/tokens/LinkToDashboardCanister.spec.ts create mode 100644 frontend/src/tests/page-objects/LinkToDashboardCanister.page-object.ts diff --git a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte index 32d3dac7027..0d3038fe3a9 100644 --- a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte +++ b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte @@ -20,7 +20,7 @@ hasAccounts, } from "$lib/utils/accounts.utils"; import { replacePlaceholders } from "$lib/utils/i18n.utils"; - import { IconDots, Island, Popover, Spinner } from "@dfinity/gix-components"; + import {IconDots, Island, Popover, Spinner, Tag} from "@dfinity/gix-components"; import type { Principal } from "@dfinity/principal"; import { TokenAmountV2, isNullish, nonNullish } from "@dfinity/utils"; import type { Writable } from "svelte/store"; @@ -30,6 +30,7 @@ import { removeImportedTokens } from "$lib/services/imported-tokens.services"; import TestIdWrapper from "$lib/components/common/TestIdWrapper.svelte"; import LinkToDashboardCanister from "$lib/components/common/LinkToDashboardCanister.svelte"; + import {isImportedToken as checkImportedToken} from "$lib/utils/imported-tokens.utils"; export let testId: string; export let accountIdentifier: string | undefined | null = undefined; @@ -177,6 +178,12 @@ let moreButton: HTMLButtonElement | undefined; let morePopupVisible = false; + + let isImportedToken = false; + $: isImportedToken = checkImportedToken({ + ledgerCanisterId, + importedTokens: $importedTokensStore.importedTokens, + }); @@ -197,6 +204,11 @@ on:nnsRemove={remove} on:nnsMore={() => console.log("icrc")} > + + {#if isImportedToken} + {$i18n.import_token.imported_token} + {/if} + {#if nonNullish(ledgerCanisterId)} + + import { IconOpenInNew } from "@dfinity/gix-components"; + import { replacePlaceholders } from "$lib/utils/i18n.utils"; + import { i18n } from "$lib/stores/i18n"; + import type { Principal } from "@dfinity/principal"; + import TestIdWrapper from "$lib/components/common/TestIdWrapper.svelte"; + + export let canisterId: Principal; + + let href: string; + $: href = replacePlaceholders($i18n.import_token.link_to_dashboard, { + $canisterId: canisterId.toText(), + }); + + + + + {$i18n.import_token.view_in_dashboard} + diff --git a/frontend/src/lib/components/universe/UniversePageSummary.svelte b/frontend/src/lib/components/universe/UniversePageSummary.svelte index f6c91fab03f..8bdc2d82092 100644 --- a/frontend/src/lib/components/universe/UniversePageSummary.svelte +++ b/frontend/src/lib/components/universe/UniversePageSummary.svelte @@ -1,28 +1,14 @@ {universe.title} - {#if importedToken} - {$i18n.import_token.imported_token} - {/if} + diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index b1667df19b2..13963e505d6 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -1049,7 +1049,6 @@ "importing": "Importing new token...", "removing": "Removing imported token...", "review_token_info": "Review token info", - "import_button": "Import", "ledger_canister_loading_error": "Unable to load token details using the provided Ledger Canister ID.", "add_imported_token_success": "New token has been successfully imported!", "remove_imported_token_success": "The token has been successfully removed!", diff --git a/frontend/src/lib/pages/NnsWallet.svelte b/frontend/src/lib/pages/NnsWallet.svelte index 1a8d201c534..1be9148e932 100644 --- a/frontend/src/lib/pages/NnsWallet.svelte +++ b/frontend/src/lib/pages/NnsWallet.svelte @@ -69,7 +69,7 @@ import { onMount, onDestroy, setContext } from "svelte"; import { writable, type Readable } from "svelte/store"; import LinkToDashboardCanister from "$lib/components/common/LinkToDashboardCanister.svelte"; - import { Principal } from "@dfinity/principal"; + import { LEDGER_CANISTER_ID } from "$lib/constants/canister-ids.constants"; $: if ($authSignedInStore) { pollAccounts(); @@ -392,9 +392,7 @@ direction="rtl" invisibleBackdrop > - + diff --git a/frontend/src/lib/types/i18n.d.ts b/frontend/src/lib/types/i18n.d.ts index 5813570b0c3..06d29058e8c 100644 --- a/frontend/src/lib/types/i18n.d.ts +++ b/frontend/src/lib/types/i18n.d.ts @@ -177,8 +177,8 @@ interface I18nAccounts { add_account: string; new_account_title: string; new_linked_subtitle: string; - attach_hardware_subtitle: string; attach_hardware_title: string; + attach_hardware_subtitle: string; attach_hardware_name_placeholder: string; attach_hardware_enter_name: string; attach_hardware_description: string; @@ -1108,7 +1108,6 @@ interface I18nImport_token { importing: string; removing: string; review_token_info: string; - import_button: string; ledger_canister_loading_error: string; add_imported_token_success: string; remove_imported_token_success: string; diff --git a/frontend/src/tests/lib/components/tokens/LinkToDashboardCanister.spec.ts b/frontend/src/tests/lib/components/tokens/LinkToDashboardCanister.spec.ts new file mode 100644 index 00000000000..3fd49791089 --- /dev/null +++ b/frontend/src/tests/lib/components/tokens/LinkToDashboardCanister.spec.ts @@ -0,0 +1,32 @@ +import LinkToDashboardCanister from "$lib/components/tokens/LinkToDashboardCanister.svelte"; +import { LinkToDashboardCanisterPo } from "$tests/page-objects/LinkToDashboardCanister.page-object"; +import { JestPageObjectElement } from "$tests/page-objects/jest.page-object"; +import { Principal } from "@dfinity/principal"; +import { render } from "@testing-library/svelte"; + +describe("LinkToDashboardCanister", () => { + const canisterIdText = "aaaaa-aa"; + const urlToDashboard = + "https://dashboard.internetcomputer.org/canister/aaaaa-aa"; + const canisterId = Principal.fromText(canisterIdText); + + const renderComponent = (props) => { + const { container } = render(LinkToDashboardCanister, { props }); + return LinkToDashboardCanisterPo.under( + new JestPageObjectElement(container) + ); + }; + + it("should render label", async () => { + const po = renderComponent({ + canisterId, + }); + expect(await po.getLabel().isPresent()).toEqual(true); + expect(await po.getLabelText()).toBe("View in Dashboard"); + }); + + it("should render href", async () => { + const po = renderComponent({ canisterId }); + expect(await po.getHref()).toBe(urlToDashboard); + }); +}); diff --git a/frontend/src/tests/lib/pages/NnsWallet.spec.ts b/frontend/src/tests/lib/pages/NnsWallet.spec.ts index c6d01899e9f..6509e0e36a0 100644 --- a/frontend/src/tests/lib/pages/NnsWallet.spec.ts +++ b/frontend/src/tests/lib/pages/NnsWallet.spec.ts @@ -241,6 +241,29 @@ describe("NnsWallet", () => { }, ]); }); + + it('should render "more" button', async () => { + const po = await renderWallet({}); + expect(await po.getMoreButton().isPresent()).toBe(true); + }); + + it('should not render "more" popup by default', async () => { + const po = await renderWallet({}); + expect(await po.getLinkToDashboardPo().isPresent()).toBe(false); + }); + + it('should have "View in dashboard" link in "more" popup', async () => { + const po = await renderWallet({}); + + await po.clickMore(); + + await runResolvedPromises(); + + expect(await po.getLinkToDashboardPo().isPresent()).toBe(true); + expect(await po.getLinkToDashboardPo().getHref()).toBe( + `https://dashboard.internetcomputer.org/canister/${OWN_CANISTER_ID_TEXT}` + ); + }); }); describe("no accounts", () => { diff --git a/frontend/src/tests/page-objects/LinkToDashboardCanister.page-object.ts b/frontend/src/tests/page-objects/LinkToDashboardCanister.page-object.ts new file mode 100644 index 00000000000..a3139ed1085 --- /dev/null +++ b/frontend/src/tests/page-objects/LinkToDashboardCanister.page-object.ts @@ -0,0 +1,24 @@ +import { BasePageObject } from "$tests/page-objects/base.page-object"; +import type { PageObjectElement } from "$tests/types/page-object.types"; + +export class LinkToDashboardCanisterPo extends BasePageObject { + private static readonly TID = "link-to-dashboard-canister-component"; + + static under(element: PageObjectElement): LinkToDashboardCanisterPo { + return new LinkToDashboardCanisterPo( + element.byTestId(LinkToDashboardCanisterPo.TID) + ); + } + + getLabel(): PageObjectElement { + return this.root.byTestId("label"); + } + + getHref(): Promise { + return this.root.getAttribute("href"); + } + + async getLabelText(): Promise { + return (await this.getLabel().getText()).trim(); + } +} diff --git a/frontend/src/tests/page-objects/NnsWallet.page-object.ts b/frontend/src/tests/page-objects/NnsWallet.page-object.ts index afbec31a0bb..ef2df8992a5 100644 --- a/frontend/src/tests/page-objects/NnsWallet.page-object.ts +++ b/frontend/src/tests/page-objects/NnsWallet.page-object.ts @@ -1,5 +1,6 @@ import type { ButtonPo } from "$tests/page-objects/Button.page-object"; import { IcpTransactionModalPo } from "$tests/page-objects/IcpTransactionModal.page-object"; +import { LinkToDashboardCanisterPo } from "$tests/page-objects/LinkToDashboardCanister.page-object"; import { SignInPo } from "$tests/page-objects/SignIn.page-object"; import { WalletPageHeaderPo } from "$tests/page-objects/WalletPageHeader.page-object"; import { WalletPageHeadingPo } from "$tests/page-objects/WalletPageHeading.page-object"; @@ -54,6 +55,14 @@ export class NnsWalletPo extends BasePageObject { return this.getButton("ledger-show-button"); } + getMoreButton(): ButtonPo { + return this.getButton("more-button"); + } + + getLinkToDashboardPo(): LinkToDashboardCanisterPo { + return LinkToDashboardCanisterPo.under(this.root); + } + hasSignInButton(): Promise { return this.getSignInPo().isPresent(); } @@ -78,6 +87,10 @@ export class NnsWalletPo extends BasePageObject { return this.getRenameButtonPo().click(); } + clickMore(): Promise { + return this.getMoreButton().click(); + } + async transferToAccount({ accountName, expectedAccountAddress, From 3ad601f5b8f1d5917d54ec48fdcf8f2337e3f411 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Wed, 14 Aug 2024 16:57:45 +0200 Subject: [PATCH 141/166] Restore missing label --- frontend/src/lib/i18n/en.json | 1 + frontend/src/lib/types/i18n.d.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index 13963e505d6..e5ad3c8d06c 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -1036,6 +1036,7 @@ }, "import_token": { "import_token": "Import Token", + "import_button": "Import", "imported_token": "Imported Token", "description": "To import a new token to your NNS dapp wallet, you will need to find, and paste the ledger canister id of the token. If you want to see your transaction history, you need to import the token’s index canister.", "ledger_label": "Ledger Canister ID", diff --git a/frontend/src/lib/types/i18n.d.ts b/frontend/src/lib/types/i18n.d.ts index 06d29058e8c..e3c2d9b5c1e 100644 --- a/frontend/src/lib/types/i18n.d.ts +++ b/frontend/src/lib/types/i18n.d.ts @@ -1095,6 +1095,7 @@ interface I18nTokens { interface I18nImport_token { import_token: string; + import_button: string; imported_token: string; description: string; ledger_label: string; From eb4b947f8402cefcea1c13a326595a0e41ecf9e4 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Thu, 15 Aug 2024 14:05:23 +0200 Subject: [PATCH 142/166] Safari table fix - Squashed commit of the following: commit 3fa7e3ff9dd8d1e62c2ecd4598528972544bdc5b Author: Max Strasinsky Date: Thu Aug 15 14:01:08 2024 +0200 Changelog commit 592830efa246bb45fee9d37a8cd5060fec259dc9 Author: Max Strasinsky Date: Thu Aug 15 13:36:49 2024 +0200 Attempt to fix safari table glitch --- frontend/src/lib/components/ui/ResponsiveTable.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/components/ui/ResponsiveTable.svelte b/frontend/src/lib/components/ui/ResponsiveTable.svelte index ad0786be724..ee0edf08a7f 100644 --- a/frontend/src/lib/components/ui/ResponsiveTable.svelte +++ b/frontend/src/lib/components/ui/ResponsiveTable.svelte @@ -185,7 +185,7 @@ border-radius: var(--border-radius); // Otherwise the non-rounded corners of the header and last row would be visible. - overflow-y: auto; + overflow-y: hidden; @include media.min-width(medium) { display: grid; From 17da1cd3f4ba47cfac9cca222dd76e04a5efeb13 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 16 Aug 2024 04:19:54 +0200 Subject: [PATCH 143/166] Formatting --- .../lib/components/accounts/IcrcWalletPage.svelte | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte index 0d3038fe3a9..4e61287962f 100644 --- a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte +++ b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte @@ -20,7 +20,13 @@ hasAccounts, } from "$lib/utils/accounts.utils"; import { replacePlaceholders } from "$lib/utils/i18n.utils"; - import {IconDots, Island, Popover, Spinner, Tag} from "@dfinity/gix-components"; + import { + IconDots, + Island, + Popover, + Spinner, + Tag, + } from "@dfinity/gix-components"; import type { Principal } from "@dfinity/principal"; import { TokenAmountV2, isNullish, nonNullish } from "@dfinity/utils"; import type { Writable } from "svelte/store"; @@ -30,7 +36,7 @@ import { removeImportedTokens } from "$lib/services/imported-tokens.services"; import TestIdWrapper from "$lib/components/common/TestIdWrapper.svelte"; import LinkToDashboardCanister from "$lib/components/common/LinkToDashboardCanister.svelte"; - import {isImportedToken as checkImportedToken} from "$lib/utils/imported-tokens.utils"; + import { isImportedToken as checkImportedToken } from "$lib/utils/imported-tokens.utils"; export let testId: string; export let accountIdentifier: string | undefined | null = undefined; @@ -206,7 +212,9 @@ > {#if isImportedToken} - {$i18n.import_token.imported_token} + {$i18n.import_token.imported_token} {/if} From 05f6380e78c95d77a93b2f6d974a0ad443fadb03 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 16 Aug 2024 04:22:03 +0200 Subject: [PATCH 144/166] cleanup: remove unused vars --- .../components/accounts/ImportTokenReview.svelte | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/frontend/src/lib/components/accounts/ImportTokenReview.svelte b/frontend/src/lib/components/accounts/ImportTokenReview.svelte index da71fa06bed..d3861a26d66 100644 --- a/frontend/src/lib/components/accounts/ImportTokenReview.svelte +++ b/frontend/src/lib/components/accounts/ImportTokenReview.svelte @@ -5,8 +5,6 @@ import type { IcrcTokenMetadata } from "$lib/types/icrc"; import Logo from "$lib/components/ui/Logo.svelte"; import ImportTokenCanisterId from "$lib/components/accounts/ImportTokenCanisterId.svelte"; - import { replacePlaceholders } from "$lib/utils/i18n.utils"; - import { isNullish } from "@dfinity/utils"; import CalloutWarning from "$lib/components/common/CalloutWarning.svelte"; export let ledgerCanisterId: Principal; @@ -14,20 +12,6 @@ export let tokenMetaData: IcrcTokenMetadata; const dispatch = createEventDispatcher(); - - let ledgerCanisterHref: string; - $: ledgerCanisterHref = replacePlaceholders( - $i18n.import_token.link_to_canister, - { - $canisterId: ledgerCanisterId.toText(), - } - ); - let indexCanisterHref: string | undefined; - $: indexCanisterHref = isNullish(indexCanisterId) - ? undefined - : replacePlaceholders($i18n.import_token.link_to_canister, { - $canisterId: ledgerCanisterId.toText(), - }); From 723dbc5101acc353aaf15a324a82e0065a067363 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 16 Aug 2024 06:32:31 +0200 Subject: [PATCH 145/166] Add remove button to the more popup --- .../components/accounts/IcrcWalletPage.svelte | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte index 4e61287962f..08be6eec3d2 100644 --- a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte +++ b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte @@ -21,7 +21,9 @@ } from "$lib/utils/accounts.utils"; import { replacePlaceholders } from "$lib/utils/i18n.utils"; import { + IconBin, IconDots, + IconOpenInNew, Island, Popover, Spinner, @@ -156,10 +158,8 @@ isSignedIn: $authSignedInStore, }))(); - const remove = async ({ - detail, - }: CustomEvent<{ ledgerCanisterId: Principal }>) => { - console.log("removeImportedToken", detail.ledgerCanisterId); + const remove = async () => { + if (isNullish(ledgerCanisterId)) return; startBusy({ initiator: "import-token-removing", @@ -169,8 +169,7 @@ const importedTokens = $importedTokensStore.importedTokens ?? []; const { success } = await removeImportedTokens({ tokensToRemove: importedTokens.filter( - ({ ledgerCanisterId: id }) => - id.toText() === detail.ledgerCanisterId.toText() + ({ ledgerCanisterId: id }) => id.toText() === ledgerCanisterId.toText() ), importedTokens, }); @@ -273,7 +272,19 @@ direction="rtl" invisibleBackdrop > - + + + {#if isImportedToken} + + + {$i18n.core.remove} + + {/if} + {/if} @@ -288,4 +299,19 @@ .info-card { background-color: var(--island-card-background); } + + .popover-content { + display: flex; + flex-direction: column; + gap: var(--padding-2x); + } + + .remove-button { + padding: 0; + color: var(--negative-emphasis); + + &:hover { + color: inherit; + } + } From ae1ed05304d53a7c49566d999187792e59c79a0e Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 16 Aug 2024 06:39:04 +0200 Subject: [PATCH 146/166] style: "more" popup buttons --- .../components/accounts/IcrcWalletPage.svelte | 2 +- .../common/LinkToDashboardCanister.svelte | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte index 08be6eec3d2..25ddc445cc2 100644 --- a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte +++ b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte @@ -311,7 +311,7 @@ color: var(--negative-emphasis); &:hover { - color: inherit; + color: var(--negative-emphasis); } } diff --git a/frontend/src/lib/components/common/LinkToDashboardCanister.svelte b/frontend/src/lib/components/common/LinkToDashboardCanister.svelte index b6112b33864..ce8c7c202d8 100644 --- a/frontend/src/lib/components/common/LinkToDashboardCanister.svelte +++ b/frontend/src/lib/components/common/LinkToDashboardCanister.svelte @@ -28,12 +28,18 @@ From fb9907d8a01ab7ca0cb8242c9cf01f0cee5fcacf Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 16 Aug 2024 06:47:10 +0200 Subject: [PATCH 147/166] style: Import button redesign --- frontend/src/lib/pages/Tokens.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/pages/Tokens.svelte b/frontend/src/lib/pages/Tokens.svelte index be95df9adb4..abc101ed21c 100644 --- a/frontend/src/lib/pages/Tokens.svelte +++ b/frontend/src/lib/pages/Tokens.svelte @@ -7,7 +7,7 @@ import { i18n } from "$lib/stores/i18n"; import type { UserToken } from "$lib/types/tokens-page"; import { heightTransition } from "$lib/utils/transition.utils"; - import { IconPlus, IconSettings } from "@dfinity/gix-components"; + import { IconAddCircle, IconSettings } from "@dfinity/gix-components"; import { Popover } from "@dfinity/gix-components"; import { nonNullish, TokenAmountV2 } from "@dfinity/utils"; import { ENABLE_IMPORT_TOKEN } from "$lib/stores/feature-flags.store"; @@ -85,10 +85,10 @@ {#if shownImportTokenButton} (showImportTokenModal = true)} > - {$i18n.import_token.import_token} + {$i18n.import_token.import_token} {/if} From 8ac4efe5b60ddb8f320604e6af5997ad1ff832b5 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 16 Aug 2024 06:54:46 +0200 Subject: [PATCH 148/166] cleanup --- frontend/src/lib/components/accounts/IcrcWalletPage.svelte | 2 -- frontend/src/lib/modals/accounts/ImportTokenModal.svelte | 5 ----- 2 files changed, 7 deletions(-) diff --git a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte index 25ddc445cc2..3824be9f75d 100644 --- a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte +++ b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte @@ -206,8 +206,6 @@ console.log("icrc")} > {#if isImportedToken} diff --git a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte index 66154f6e375..ff9e2b404ab 100644 --- a/frontend/src/lib/modals/accounts/ImportTokenModal.svelte +++ b/frontend/src/lib/modals/accounts/ImportTokenModal.svelte @@ -113,11 +113,6 @@ (nonNullish(indexCanisterId) ? await matchLedgerIndexPair({ ledgerCanisterId, indexCanisterId }) : true); - console.log( - "validOrEmptyIndexCanister", - validOrEmptyIndexCanister, - tokenMetaData - ); stopBusy("import-token-validation"); From ced1d8b6ce3e2f6cf57c9fc4c4f2be088f9b7ef0 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 16 Aug 2024 09:12:05 +0200 Subject: [PATCH 149/166] feat: remove imported token confirmation dialog (ImportTokenRemoveConfirmation) --- .../components/accounts/IcrcWalletPage.svelte | 14 +++- .../ImportTokenRemoveConfirmation.svelte | 67 +++++++++++++++++++ frontend/src/lib/i18n/en.json | 4 +- frontend/src/lib/types/i18n.d.ts | 2 + 4 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 frontend/src/lib/components/accounts/ImportTokenRemoveConfirmation.svelte diff --git a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte index 3824be9f75d..461356bd779 100644 --- a/frontend/src/lib/components/accounts/IcrcWalletPage.svelte +++ b/frontend/src/lib/components/accounts/IcrcWalletPage.svelte @@ -23,7 +23,6 @@ import { IconBin, IconDots, - IconOpenInNew, Island, Popover, Spinner, @@ -39,6 +38,7 @@ import TestIdWrapper from "$lib/components/common/TestIdWrapper.svelte"; import LinkToDashboardCanister from "$lib/components/common/LinkToDashboardCanister.svelte"; import { isImportedToken as checkImportedToken } from "$lib/utils/imported-tokens.utils"; + import ImportTokenRemoveConfirmation from "$lib/components/accounts/ImportTokenRemoveConfirmation.svelte"; export let testId: string; export let accountIdentifier: string | undefined | null = undefined; @@ -189,6 +189,8 @@ ledgerCanisterId, importedTokens: $importedTokensStore.importedTokens, }); + + let removeImportedTokenConfirmtionVisible = false; @@ -276,7 +278,7 @@ (removeImportedTokenConfirmtionVisible = true)} > {$i18n.core.remove} @@ -285,6 +287,14 @@