Skip to content

Commit

Permalink
Skip failed balance reload (#5550)
Browse files Browse the repository at this point in the history
# Motivation

Currently, on the tokens page, there is a flag-based mechanism to
prevent reloading of token data
([here](https://github.com/dfinity/nns-dapp/blob/001f6f4f3a79889045fd262f75052d4992824c47/frontend/src/routes/(app)/(nns)/tokens/%2Bpage.svelte#L69)
and
[here](https://github.com/dfinity/nns-dapp/blob/001f6f4f3a79889045fd262f75052d4992824c47/frontend/src/routes/(app)/(nns)/tokens/%2Bpage.svelte#L83)).
This is applied to the Sns and ckBTC tokens but not to the ICRC tokens,
as the ICRC token list was previously static. Now, when the dapp fails
to load a token, the failed token is removed from the ICRC token list,
which triggers a reload of all ICRC token data. To prevent this, we
apply the same flag mechanism to avoid unnecessary reloading.

# Changes

- Memorize the loaded ICRC token IDs and reload only new ones.

# Tests

- Tested that there is no data reload after an imported token fails and
verified that the test fails without the fix.

# Todos

- [ ] Add entry to changelog (if necessary).
Not necessary.
  • Loading branch information
mstrasinskis authored Oct 8, 2024
1 parent d1cb9be commit 76f74fe
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 19 deletions.
61 changes: 42 additions & 19 deletions frontend/src/routes/(app)/(nns)/tokens/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -48,36 +48,51 @@
import ImportTokenRemoveConfirmation from "$lib/components/accounts/ImportTokenRemoveConfirmation.svelte";
import { isUserTokenData } from "$lib/utils/user-token.utils";
import { removeImportedTokens } from "$lib/services/imported-tokens.services";
import type { CanisterIdString } from "@dfinity/nns";
onMount(() => {
loadCkBTCTokens();
});
let loadSnsAccountsBalancesRequested = false;
let loadCkBTCAccountsBalancesRequested = false;
const loadedIcrcAccountsBalancesRequested = new Set<CanisterIdString>();
const getAndUpdateNotLoadedIds = (canisterIds: CanisterIdString[]) => {
const ids = canisterIds.filter(
(id) => !loadedIcrcAccountsBalancesRequested.has(id)
);
ids.forEach((id) => loadedIcrcAccountsBalancesRequested.add(id));
return ids;
};
const loadSnsAccountsBalances = async (projects: SnsFullProject[]) => {
// We start when the projects are fetched
if (projects.length === 0) {
return;
}
const rootCanisterIds = projects.map(({ rootCanisterId }) =>
rootCanisterId.toText()
);
const notLoadedCanisterIds = getAndUpdateNotLoadedIds(rootCanisterIds);
// We trigger the loading of the Sns Accounts Balances only once
if (loadSnsAccountsBalancesRequested) {
if (notLoadedCanisterIds.length === 0) {
return;
}
loadSnsAccountsBalancesRequested = true;
await uncertifiedLoadSnsesAccountsBalances({
rootCanisterIds: projects.map(({ rootCanisterId }) => rootCanisterId),
rootCanisterIds: notLoadedCanisterIds.map((id) => Principal.fromText(id)),
excludeRootCanisterIds: [],
});
};
const loadCkBTCAccountsBalances = async (universes: Universe[]) => {
// We trigger the loading of the ckBTC Accounts Balances only once
if (loadCkBTCAccountsBalancesRequested) {
const canisterIds = universes.map(
(universe: Universe) => universe.canisterId
);
const notLoadedCanisterIds = getAndUpdateNotLoadedIds(canisterIds);
if (notLoadedCanisterIds.length === 0) {
return;
}
Expand All @@ -88,6 +103,10 @@
* There is also a "Check for incoming BTC" button in the Wallet page.
*/
universes.forEach((universe: Universe) => {
if (!notLoadedCanisterIds.includes(universe.canisterId)) {
return;
}
const ckBTCCanisters = CKBTC_ADDITIONAL_CANISTERS[universe.canisterId];
if (nonNullish(ckBTCCanisters.minterCanisterId)) {
updateBalance({
Expand All @@ -100,15 +119,19 @@
}
});
loadCkBTCAccountsBalancesRequested = true;
await loadAccountsBalances(universes.map(({ canisterId }) => canisterId));
};
const loadIcrcTokenAccounts = async (
icrcCanisters: IcrcCanistersStoreData
) => {
await loadAccountsBalances(Object.keys(icrcCanisters));
const ids = Object.keys(icrcCanisters);
const notLoadedCanisterIds = getAndUpdateNotLoadedIds(ids);
// Skip loading if there are no new ids
if (notLoadedCanisterIds.length === 0) {
return;
}
await loadAccountsBalances(notLoadedCanisterIds);
};
const loadAccountsBalances = async (
Expand Down Expand Up @@ -138,15 +161,15 @@
return loadAccountsBalances([universeId.toText()]);
};
$: (async () => {
if ($authSignedInStore) {
await Promise.allSettled([
loadSnsAccountsBalances($snsProjectsCommittedStore),
loadCkBTCAccountsBalances($ckBTCUniversesStore),
loadIcrcTokenAccounts($icrcCanistersStore),
]);
}
})();
$: if ($authSignedInStore) {
loadSnsAccountsBalances($snsProjectsCommittedStore);
}
$: if ($authSignedInStore) {
loadCkBTCAccountsBalances($ckBTCUniversesStore);
}
$: if ($authSignedInStore) {
loadIcrcTokenAccounts($icrcCanistersStore);
}
type ModalType =
| "sns-send"
Expand Down
34 changes: 34 additions & 0 deletions frontend/src/tests/routes/app/tokens/page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,40 @@ describe("Tokens route", () => {
"Pacman",
]);
});

it("should not reload balances after an imported token becomes failed", async () => {
const po = await renderPage();
const rows = await po.getTokensPagePo().getTokensTable().getRows();
const notFailedTokenCount = 8;
expect(
(
await Promise.all(
rows.map(
async (row) =>
!(await row.getFailedTokenTooltipPo().isPresent())
)
)
).filter(Boolean).length
).toEqual(notFailedTokenCount);

await runResolvedPromises();
expect(icrcLedgerApi.queryIcrcBalance).toBeCalledTimes(
notFailedTokenCount
);

// Add a failed token
expect(
get(failedImportedTokenLedgerIdsStore).includes(
importedToken2Id.toText()
)
).toEqual(false);
failedImportedTokenLedgerIdsStore.add(importedToken2Id.toText());

await runResolvedPromises();
expect(icrcLedgerApi.queryIcrcBalance).toBeCalledTimes(
notFailedTokenCount
);
});
});

describe("when logged out", () => {
Expand Down

0 comments on commit 76f74fe

Please sign in to comment.