diff --git a/packages/desktop/components/menus/TokenActionsMenu.svelte b/packages/desktop/components/menus/TokenActionsMenu.svelte index 2442922c1c..009c14550f 100644 --- a/packages/desktop/components/menus/TokenActionsMenu.svelte +++ b/packages/desktop/components/menus/TokenActionsMenu.svelte @@ -23,7 +23,7 @@ } function onUnverifyClick(): void { - unverifyToken(token.id, NotVerifiedStatus.Skipped) + unverifyToken(token, NotVerifiedStatus.Skipped) updatePopupProps({ token: { ...token, verification: { verified: false, status: NotVerifiedStatus.Skipped } }, }) @@ -31,7 +31,7 @@ } function onVerifyClick(): void { - verifyToken(token.id, VerifiedStatus.SelfVerified) + verifyToken(token, VerifiedStatus.SelfVerified) updatePopupProps({ token: { ...token, verification: { verified: true, status: VerifiedStatus.SelfVerified } }, }) @@ -39,7 +39,7 @@ } function onUnhideClick(): void { - unhideToken(token.id) + unhideToken(token) hideActivitiesForHiddenTokens() updatePopupProps({ token: { ...token, hidden: false }, @@ -48,7 +48,7 @@ } function onHideClick(): void { - hideToken(token.id) + hideToken(token) hideActivitiesForHiddenTokens() updatePopupProps({ token: { ...token, hidden: true }, diff --git a/packages/desktop/components/menus/TokenListMenu.svelte b/packages/desktop/components/menus/TokenListMenu.svelte index 1b10142fac..8b0611976a 100644 --- a/packages/desktop/components/menus/TokenListMenu.svelte +++ b/packages/desktop/components/menus/TokenListMenu.svelte @@ -3,7 +3,7 @@ import { showNotification } from '@auxiliary/notification' import { IconName, Menu } from '@bloomwalletio/ui' import { localize } from '@core/i18n' - import { refreshAccountTokensForActiveProfile } from '@core/token/actions' + import { loadTokensForAllAccountBalances } from '@core/token/actions' import { PopupId, closePopup, openPopup } from '../../lib/auxiliary/popup' import { fetchL2BalanceForAllAccounts } from '@core/layer-2' @@ -27,7 +27,7 @@ } function refreshTokenMetadata(): void { - refreshAccountTokensForActiveProfile(true) + loadTokensForAllAccountBalances(true) showNotification({ variant: 'success', text: localize('notifications.refreshTokenMetadata.success'), diff --git a/packages/desktop/components/popup/popups/FaucetRequestPopup.svelte b/packages/desktop/components/popup/popups/FaucetRequestPopup.svelte index adce77816c..cdc9b7eb8b 100644 --- a/packages/desktop/components/popup/popups/FaucetRequestPopup.svelte +++ b/packages/desktop/components/popup/popups/FaucetRequestPopup.svelte @@ -6,11 +6,12 @@ import { Error } from '@bloomwalletio/ui' import { handleError } from '@core/error/handlers/handleError' import PopupTemplate from '../PopupTemplate.svelte' - import { getBaseToken } from '@core/profile/actions' let isBusy = false let error: string | undefined + const network = getL1Network() + async function onConfirmClick(): Promise { error = undefined try { @@ -33,7 +34,7 @@ { if (hasUsedWalletFinder) { const profileId = getActiveProfileId() - await refreshAccountTokensForActiveProfile() + await loadTokensForAllAccountBalances() await generateAndStoreActivitiesForAllAccounts(profileId) loadNftsForActiveProfile() } diff --git a/packages/desktop/components/popup/popups/TokenInformationPopup.svelte b/packages/desktop/components/popup/popups/TokenInformationPopup.svelte index dec1772c4e..945270b70f 100644 --- a/packages/desktop/components/popup/popups/TokenInformationPopup.svelte +++ b/packages/desktop/components/popup/popups/TokenInformationPopup.svelte @@ -11,13 +11,13 @@ import { SendFlowRoute, SendFlowRouter, sendFlowRouter } from '@views/dashboard/send-flow' import PopupTemplate from '../PopupTemplate.svelte' - export let token: ITokenWithBalance | undefined + export let token: ITokenWithBalance export let activityId: string | undefined = undefined - $: isNewToken = token?.verification?.status === NotVerifiedStatus.New + $: isNewToken = token.verification?.status === NotVerifiedStatus.New function onSkipClick(): void { - unverifyToken(token?.id, NotVerifiedStatus.Skipped) + unverifyToken(token, NotVerifiedStatus.Skipped) if (activityId) { openPopup({ id: PopupId.ActivityDetails, @@ -31,7 +31,7 @@ } function onVerifyClick(): void { - verifyToken(token?.id, VerifiedStatus.SelfVerified) + verifyToken(token, VerifiedStatus.SelfVerified) if (activityId) { openPopup({ id: PopupId.ActivityDetails, @@ -45,7 +45,7 @@ } function onSendClick(): void { - const sendFlowType = token?.id === BASE_TOKEN_ID ? SendFlowType.BaseCoinTransfer : SendFlowType.TokenTransfer + const sendFlowType = token.id === BASE_TOKEN_ID ? SendFlowType.BaseCoinTransfer : SendFlowType.TokenTransfer setSendFlowParameters({ type: sendFlowType, [sendFlowType]: { @@ -62,7 +62,7 @@
- {#if token?.standard === TokenStandard.Irc30 || token?.standard === TokenStandard.Erc20} + {#if token.standard === TokenStandard.Irc30 || token.standard === TokenStandard.Erc20} {/if}
diff --git a/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte b/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte index 3782b581c4..b6da55e5f0 100644 --- a/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte +++ b/packages/desktop/views/dashboard/send-flow/views/SelectRecipientView.svelte @@ -42,17 +42,22 @@ $: selectedNetworkId = selectorOptions[selectedIndex]?.networkId $: selectedRecipient = selectorOptions[selectedIndex]?.selectedRecipient - let hasNetworkRecipientError: boolean = false - $: { + let hasInsufficientFunds = false + $: $sendFlowParameters, void checkFundsForGas() + async function checkFundsForGas(): Promise { + if (!$sendFlowParameters) { + return + } + const originNetworkId = getNetworkIdFromSendFlowParameters($sendFlowParameters) if (originNetworkId && isEvmNetwork(originNetworkId)) { - hasNetworkRecipientError = !canAccountMakeEvmTransaction( + hasInsufficientFunds = !(await canAccountMakeEvmTransaction( $selectedAccountIndex, originNetworkId, - $sendFlowParameters?.type - ) + $sendFlowParameters.type + )) } else { - hasNetworkRecipientError = false + hasInsufficientFunds = false } } @@ -247,13 +252,13 @@ >
- {#if hasNetworkRecipientError} + {#if hasInsufficientFunds} {/if}
diff --git a/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte b/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte index a6828e77cd..f26236b463 100644 --- a/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte +++ b/packages/desktop/views/dashboard/send-flow/views/SelectTokenView.svelte @@ -31,21 +31,21 @@ $: $selectedAccountTokens, searchValue, selectedTab, setFilteredTokenList() - let tokenError: string = '' - $: if ( - selectedToken && - isEvmNetwork(selectedToken.networkId) && - !canAccountMakeEvmTransaction($selectedAccountIndex, selectedToken.networkId, $sendFlowParameters?.type) - ) { - tokenError = localize('error.send.insufficientFundsTransaction') - } else if ( - selectedToken && - isStardustNetwork(selectedToken.networkId) && - !canAccountMakeStardustTransaction($selectedAccountIndex, $sendFlowParameters?.type) - ) { - tokenError = localize('error.send.insufficientFundsTransaction') - } else { - tokenError = '' + let tokenError = '' + $: selectedToken, $sendFlowParameters, void setTokenError() + async function setTokenError(): Promise { + let hasEnoughFunds = true + if (selectedToken && isEvmNetwork(selectedToken.networkId)) { + hasEnoughFunds = await canAccountMakeEvmTransaction( + $selectedAccountIndex, + selectedToken.networkId, + $sendFlowParameters?.type + ) + } else if (selectedToken && isStardustNetwork(selectedToken.networkId)) { + hasEnoughFunds = canAccountMakeStardustTransaction($selectedAccountIndex, $sendFlowParameters?.type) + } + + tokenError = hasEnoughFunds ? '' : localize('error.send.insufficientFundsTransaction') } const tabs = [ diff --git a/packages/desktop/views/dashboard/wallet/panes/account-summary/AccountSummaryPane.svelte b/packages/desktop/views/dashboard/wallet/panes/account-summary/AccountSummaryPane.svelte index a437b160bf..5f1950b1c6 100644 --- a/packages/desktop/views/dashboard/wallet/panes/account-summary/AccountSummaryPane.svelte +++ b/packages/desktop/views/dashboard/wallet/panes/account-summary/AccountSummaryPane.svelte @@ -5,15 +5,18 @@ import { networks } from '@core/network' export let account: IAccountState + + const GRID_COLS = { + 0: 'grid-cols-1', + 1: 'grid-cols-2', + 2: 'grid-cols-3', + 3: 'grid-cols-4', + } import { Table } from '@bloomwalletio/ui' import { getFormattedTimeStamp, localize } from '@core/i18n' - import { NetworkId } from '@core/network' - import { getBaseToken } from '@core/profile/actions' + import { NetworkId, getNetwork } from '@core/network' import { formatTokenAmountBestMatch } from '@core/token' import { NetworkLabel } from '@ui' export let time: Date + export let sourceNetworkId: NetworkId export let destinationNetworkId: NetworkId export let maxGasFee: bigint | undefined = undefined export let transactionFee: bigint | undefined = undefined @@ -17,7 +17,7 @@ $: formattedTransactionFee = formatAmount(transactionFee) function formatAmount(amount: bigint | undefined): string | undefined { - return amount ? formatTokenAmountBestMatch(amount, getBaseToken()) : undefined + return amount ? formatTokenAmountBestMatch(amount, getNetwork(sourceNetworkId)?.baseToken) : undefined } diff --git a/packages/shared/src/components/activities/stardust/StardustActivityInformation.svelte b/packages/shared/src/components/activities/stardust/StardustActivityInformation.svelte index 35a970a3a8..40106c9a31 100644 --- a/packages/shared/src/components/activities/stardust/StardustActivityInformation.svelte +++ b/packages/shared/src/components/activities/stardust/StardustActivityInformation.svelte @@ -52,7 +52,7 @@ case StardustActivityType.Foundry: tabs = getTabItems([PopupTab.Transaction, PopupTab.Foundry, PopupTab.Token]) token = activity.tokenTransfer - ? getPersistedToken(activity.tokenTransfer?.tokenId)?.metadata + ? getPersistedToken(activity.sourceNetworkId, activity.tokenTransfer?.tokenId)?.metadata : undefined break case StardustActivityType.Consolidation: diff --git a/packages/shared/src/components/activities/stardust/info/StardustGenericInformation.svelte b/packages/shared/src/components/activities/stardust/info/StardustGenericInformation.svelte index 95f9894413..7d58394385 100644 --- a/packages/shared/src/components/activities/stardust/info/StardustGenericInformation.svelte +++ b/packages/shared/src/components/activities/stardust/info/StardustGenericInformation.svelte @@ -4,8 +4,7 @@ import { openUrlInBrowser } from '@core/app' import { time } from '@core/app/stores' import { getFormattedTimeStamp, localize } from '@core/i18n' - import { ExplorerEndpoint, getDefaultExplorerUrl } from '@core/network' - import { getBaseToken } from '@core/profile/actions' + import { ExplorerEndpoint, getDefaultExplorerUrl, getNetwork } from '@core/network' import { formatTokenAmountBestMatch } from '@core/token' import { buildUrl } from '@core/utils' import { getTimeDifference } from '@core/utils/time' @@ -32,7 +31,7 @@ } function formatAmount(amount: bigint | undefined): string | undefined { - return amount ? formatTokenAmountBestMatch(amount, getBaseToken()) : undefined + return amount ? formatTokenAmountBestMatch(amount, getNetwork(activity.sourceNetworkId)?.baseToken) : undefined } diff --git a/packages/shared/src/components/activities/stardust/info/StardustTokenInformation.svelte b/packages/shared/src/components/activities/stardust/info/StardustTokenInformation.svelte index e65624d7b2..a22ac80ec9 100644 --- a/packages/shared/src/components/activities/stardust/info/StardustTokenInformation.svelte +++ b/packages/shared/src/components/activities/stardust/info/StardustTokenInformation.svelte @@ -10,7 +10,10 @@ let metadata: IIrc30Metadata | undefined $: metadata = ( - getPersistedToken(activity.tokenTransfer?.tokenId ?? activity.baseTokenTransfer.tokenId)?.metadata + getPersistedToken( + activity.sourceNetworkId, + activity.tokenTransfer?.tokenId ?? activity.baseTokenTransfer.tokenId + )?.metadata ) diff --git a/packages/shared/src/components/avatars/NetworkAvatar.svelte b/packages/shared/src/components/avatars/NetworkAvatar.svelte index 4d23cee9c5..c430402e4a 100644 --- a/packages/shared/src/components/avatars/NetworkAvatar.svelte +++ b/packages/shared/src/components/avatars/NetworkAvatar.svelte @@ -1,7 +1,7 @@ - - + {#if showTooltip && networkName} diff --git a/packages/shared/src/lib/core/activity/actions/loadAssetsForAllAccounts.ts b/packages/shared/src/lib/core/activity/actions/loadAssetsForAllAccounts.ts index 30cf300452..726f1bd358 100644 --- a/packages/shared/src/lib/core/activity/actions/loadAssetsForAllAccounts.ts +++ b/packages/shared/src/lib/core/activity/actions/loadAssetsForAllAccounts.ts @@ -3,25 +3,34 @@ import { IPersistedToken } from '@core/token/interfaces' import { getOrRequestTokenFromPersistedTokens } from '@core/token/actions' import { addPersistedToken } from '@core/token/stores' import { get } from 'svelte/store' -import { StardustActivityType } from '../enums' import { allAccountActivities } from '../stores' +import { NetworkId } from '@core/network/types' +import { getTokenIdFromActivity } from '../utils' export async function loadAssetsForAllActivities(account: IAccountState): Promise { const accountActivities = get(allAccountActivities)[account.index] - const persistedTokens: IPersistedToken[] = [] + const tokens: { [networkId: NetworkId]: IPersistedToken[] } = {} for (const activity of accountActivities) { try { - if (activity.type === StardustActivityType.Basic || activity.type === StardustActivityType.Foundry) { - const tokenId = activity.tokenTransfer?.tokenId ?? activity.baseTokenTransfer?.tokenId - const token = await getOrRequestTokenFromPersistedTokens(tokenId, activity.sourceNetworkId, false) - if (token) { - persistedTokens.push(token) + const tokenId = getTokenIdFromActivity(activity) + if (!tokenId) { + continue + } + + const token = await getOrRequestTokenFromPersistedTokens(tokenId, activity.sourceNetworkId, false) + if (token) { + if (!tokens[activity.sourceNetworkId]) { + tokens[activity.sourceNetworkId] = [] } + tokens[activity.sourceNetworkId].push(token) } } catch (err) { console.error(err) } } - addPersistedToken(...persistedTokens) + + for (const networkId of Object.keys(tokens)) { + addPersistedToken(networkId as NetworkId, ...tokens[networkId]) + } } diff --git a/packages/shared/src/lib/core/activity/actions/setAsyncStatusOfAccountActivities.ts b/packages/shared/src/lib/core/activity/actions/setAsyncStatusOfAccountActivities.ts index 4dd26e33a5..0c989eea6f 100644 --- a/packages/shared/src/lib/core/activity/actions/setAsyncStatusOfAccountActivities.ts +++ b/packages/shared/src/lib/core/activity/actions/setAsyncStatusOfAccountActivities.ts @@ -1,6 +1,6 @@ import { syncBalance } from '@core/account/actions/syncBalance' import { updateNftInAllAccountNftsForAccount } from '@core/nfts/actions' -import { refreshAccountTokensForActiveProfile } from '@core/token/actions' +import { loadTokensForAllAccountBalances } from '@core/token/actions' import { StardustActivityAsyncStatus, ActivityDirection, StardustActivityType } from '../enums' import { allAccountActivities } from '../stores' import { getAsyncStatus } from '../utils/helper' @@ -55,6 +55,6 @@ export function setAsyncStatusOfAccountActivities(time: Date): void { syncBalance(accountIndex) } if (balancesToUpdate.length) { - void refreshAccountTokensForActiveProfile() + void loadTokensForAllAccountBalances() } } diff --git a/packages/shared/src/lib/core/activity/stores/selected-account-activities.store.ts b/packages/shared/src/lib/core/activity/stores/selected-account-activities.store.ts index be180d5d8e..741d95cc2d 100644 --- a/packages/shared/src/lib/core/activity/stores/selected-account-activities.store.ts +++ b/packages/shared/src/lib/core/activity/stores/selected-account-activities.store.ts @@ -41,7 +41,7 @@ export const queriedActivities: Readable = derived( } const tokenId = _activity.tokenTransfer?.tokenId ?? _activity.baseTokenTransfer.tokenId - const token = containsAssets ? getPersistedToken(tokenId) : undefined + const token = containsAssets ? getPersistedToken(_activity.sourceNetworkId, tokenId) : undefined const hasValidAsset = token?.metadata && isValidIrc30Token(token.metadata) return !_activity.isHidden && hasValidAsset } else if (_activity.namespace === NetworkNamespace.Evm) { @@ -84,20 +84,12 @@ function getFieldsToSearchFromActivity(activity: Activity): string[] { fieldsToSearch.push(tokenId) fieldsToSearch.push(String(rawAmount)) - const tokenName = getPersistedToken(tokenId)?.metadata?.name + const tokenName = getPersistedToken(activity.sourceNetworkId, tokenId)?.metadata?.name if (tokenName) { fieldsToSearch.push(tokenName) } - fieldsToSearch.push( - getFormattedAmountFromActivity( - rawAmount, - tokenId, - activity.direction, - activity.action, - false - )?.toLowerCase() - ) + fieldsToSearch.push(getFormattedAmountFromActivity(rawAmount, tokenId, activity, false)?.toLowerCase()) } } else if (activity.namespace === NetworkNamespace.Evm) { if (activity.type === EvmActivityType.CoinTransfer) { @@ -107,8 +99,7 @@ function getFieldsToSearchFromActivity(activity: Activity): string[] { getFormattedAmountFromActivity( activity.baseTokenTransfer.rawAmount, activity.baseTokenTransfer.tokenId, - activity.direction, - activity.action, + activity, false )?.toLowerCase() ) @@ -119,20 +110,12 @@ function getFieldsToSearchFromActivity(activity: Activity): string[] { fieldsToSearch.push(tokenId) if (standard === TokenStandard.Erc20 || standard === TokenStandard.Irc30) { - const tokenName = getPersistedToken(tokenId)?.metadata?.name + const tokenName = getPersistedToken(activity.sourceNetworkId, tokenId)?.metadata?.name if (tokenName) { fieldsToSearch.push(tokenName) } - fieldsToSearch.push( - getFormattedAmountFromActivity( - rawAmount, - tokenId, - activity.direction, - activity.action, - false - )?.toLowerCase() - ) + fieldsToSearch.push(getFormattedAmountFromActivity(rawAmount, tokenId, activity, false)?.toLowerCase()) } } } diff --git a/packages/shared/src/lib/core/activity/utils/convertActvitiesToCsv.ts b/packages/shared/src/lib/core/activity/utils/convertActvitiesToCsv.ts index 047188bb20..bff52b030f 100644 --- a/packages/shared/src/lib/core/activity/utils/convertActvitiesToCsv.ts +++ b/packages/shared/src/lib/core/activity/utils/convertActvitiesToCsv.ts @@ -98,11 +98,13 @@ function getRowForStardustActivity( let assetTicker: string | undefined let amount: string | undefined - const baseCoinMetadata = getPersistedToken(BASE_TOKEN_ID)?.metadata as IBaseToken + const baseCoinMetadata = getPersistedToken(activity.sourceNetworkId, BASE_TOKEN_ID)?.metadata as IBaseToken if (activity.type === StardustActivityType.Basic) { if (activity.tokenTransfer) { const tokenId = activity.tokenTransfer.tokenId - const metadata = getPersistedToken(tokenId)?.metadata as IErc20Metadata | IIrc30Metadata + const metadata = getPersistedToken(activity.sourceNetworkId, tokenId)?.metadata as + | IErc20Metadata + | IIrc30Metadata amount = metadata ? formatTokenAmountBestMatch(activity.tokenTransfer.rawAmount, metadata, { round: false, @@ -201,7 +203,7 @@ function getRowForEvmActivity( let assetName: string | undefined let assetTicker: string | undefined let amount: string | undefined - const baseCoinMetadata = getPersistedToken(BASE_TOKEN_ID)?.metadata as IBaseToken + const baseCoinMetadata = getPersistedToken(activity.sourceNetworkId, BASE_TOKEN_ID)?.metadata as IBaseToken if (activity.type === EvmActivityType.CoinTransfer) { amount = baseCoinMetadata @@ -219,7 +221,9 @@ function getRowForEvmActivity( } else if (isEvmTokenActivity(activity)) { const { standard, tokenId, rawAmount } = activity.tokenTransfer if (standard === TokenStandard.Erc20 || standard === TokenStandard.Irc30) { - const metadata = getPersistedToken(tokenId)?.metadata as IErc20Metadata | IIrc30Metadata + const metadata = getPersistedToken(activity.sourceNetworkId, tokenId)?.metadata as + | IErc20Metadata + | IIrc30Metadata amount = metadata ? formatTokenAmountBestMatch(rawAmount, metadata, { round: false, withUnit: false }) : '' assetId = tokenId diff --git a/packages/shared/src/lib/core/activity/utils/getTokenFromActivity.ts b/packages/shared/src/lib/core/activity/utils/getTokenFromActivity.ts index a9c54dbb7b..8d631cf7cb 100644 --- a/packages/shared/src/lib/core/activity/utils/getTokenFromActivity.ts +++ b/packages/shared/src/lib/core/activity/utils/getTokenFromActivity.ts @@ -1,42 +1,13 @@ -import { BASE_TOKEN_ID, ITokenWithBalance, TokenStandard } from '@core/token' +import { ITokenWithBalance } from '@core/token' import { Activity } from '../types' import { getTokenFromSelectedAccountTokens } from '@core/token/stores' -import { StardustActivityType } from '../enums' -import { NetworkNamespace } from '@core/network' -import { EvmActivityType } from '../enums/evm' -import { isEvmTokenActivity } from './isEvmTokenActivity' +import { getTokenIdFromActivity } from './getTokenIdFromActivity' export function getTokenFromActivity(activity: Activity): ITokenWithBalance | undefined { - if (activity.namespace === NetworkNamespace.Stardust) { - if (activity.type === StardustActivityType.Basic || activity.type === StardustActivityType.Foundry) { - return getTokenFromSelectedAccountTokens( - activity.tokenTransfer?.tokenId ?? activity.baseTokenTransfer.tokenId, - activity.sourceNetworkId - ) - } else if ( - activity.type === StardustActivityType.Governance || - activity.type === StardustActivityType.Consolidation - ) { - return getTokenFromSelectedAccountTokens(BASE_TOKEN_ID, activity.sourceNetworkId) - } else { - return undefined - } - } else if (activity.namespace === NetworkNamespace.Evm) { - if (activity.type === EvmActivityType.CoinTransfer) { - return getTokenFromSelectedAccountTokens(BASE_TOKEN_ID, activity.sourceNetworkId) - } else if (isEvmTokenActivity(activity)) { - if ( - activity.tokenTransfer.standard === TokenStandard.Erc20 || - activity.tokenTransfer.standard === TokenStandard.Irc30 - ) { - return getTokenFromSelectedAccountTokens(activity.tokenTransfer.tokenId, activity.sourceNetworkId) - } else { - return undefined - } - } else { - return undefined - } - } else { + const tokenId = getTokenIdFromActivity(activity) + if (!tokenId) { return undefined } + + return getTokenFromSelectedAccountTokens(tokenId, activity.sourceNetworkId) } diff --git a/packages/shared/src/lib/core/activity/utils/getTokenIdFromActivity.ts b/packages/shared/src/lib/core/activity/utils/getTokenIdFromActivity.ts new file mode 100644 index 0000000000..3d7ef4b81c --- /dev/null +++ b/packages/shared/src/lib/core/activity/utils/getTokenIdFromActivity.ts @@ -0,0 +1,38 @@ +import { BASE_TOKEN_ID, TokenStandard } from '@core/token' +import { Activity } from '../types' +import { StardustActivityType } from '../enums' +import { NetworkNamespace } from '@core/network' +import { EvmActivityType } from '../enums/evm' +import { isEvmTokenActivity } from './isEvmTokenActivity' + +export function getTokenIdFromActivity(activity: Activity): string | undefined { + if (activity.namespace === NetworkNamespace.Stardust) { + if (activity.type === StardustActivityType.Basic || activity.type === StardustActivityType.Foundry) { + return activity.tokenTransfer?.tokenId ?? activity.baseTokenTransfer.tokenId + } else if ( + activity.type === StardustActivityType.Governance || + activity.type === StardustActivityType.Consolidation + ) { + return BASE_TOKEN_ID + } else { + return undefined + } + } else if (activity.namespace === NetworkNamespace.Evm) { + if (activity.type === EvmActivityType.CoinTransfer) { + return BASE_TOKEN_ID + } else if (isEvmTokenActivity(activity)) { + if ( + activity.tokenTransfer.standard === TokenStandard.Erc20 || + activity.tokenTransfer.standard === TokenStandard.Irc30 + ) { + return activity.tokenTransfer.tokenId + } else { + return undefined + } + } else { + return undefined + } + } else { + return undefined + } +} diff --git a/packages/shared/src/lib/core/activity/utils/getTransactionAssets.ts b/packages/shared/src/lib/core/activity/utils/getTransactionAssets.ts index 8aa2eebbad..2f23133cf8 100644 --- a/packages/shared/src/lib/core/activity/utils/getTransactionAssets.ts +++ b/packages/shared/src/lib/core/activity/utils/getTransactionAssets.ts @@ -17,7 +17,10 @@ export function getTransactionAssets( baseCoinTransfer?: TokenTransferData } | undefined { - const baseCoin = { ...getPersistedToken(BASE_TOKEN_ID), networkId: activity.sourceNetworkId } + const baseCoin = { + ...getPersistedToken(activity.sourceNetworkId, BASE_TOKEN_ID), + networkId: activity.sourceNetworkId, + } if (!baseCoin) { return undefined @@ -39,7 +42,10 @@ export function getTransactionAssets( } } else if (activity.type === StardustActivityType.Basic || activity.type === StardustActivityType.Foundry) { const token: IToken | undefined = activity.tokenTransfer?.tokenId - ? { ...getPersistedToken(activity.tokenTransfer.tokenId), networkId: activity.sourceNetworkId } + ? { + ...getPersistedToken(activity.sourceNetworkId, activity.tokenTransfer.tokenId), + networkId: activity.sourceNetworkId, + } : undefined const tokenAmount = activity.tokenTransfer?.rawAmount diff --git a/packages/shared/src/lib/core/activity/utils/index.ts b/packages/shared/src/lib/core/activity/utils/index.ts index c52fea75ce..79cb15498d 100644 --- a/packages/shared/src/lib/core/activity/utils/index.ts +++ b/packages/shared/src/lib/core/activity/utils/index.ts @@ -6,6 +6,8 @@ export * from './getActivityActionPill' export * from './getActivityTileAction' export * from './getActivityTileAsset' export * from './getTransactionAssets' +export * from './getTokenIdFromActivity' +export * from './getTokenFromActivity' export * from './isEvmTokenActivity' export * from './isVisibleActivity' diff --git a/packages/shared/src/lib/core/activity/utils/isVisibleActivity.ts b/packages/shared/src/lib/core/activity/utils/isVisibleActivity.ts index f4f3a9ab04..baace0f120 100644 --- a/packages/shared/src/lib/core/activity/utils/isVisibleActivity.ts +++ b/packages/shared/src/lib/core/activity/utils/isVisibleActivity.ts @@ -144,7 +144,7 @@ function isVisibleWithActiveAmountFilter(activity: Activity, filter: ActivityFil } else { return true } - const token = getPersistedToken(tokenId) + const token = getPersistedToken(activity.sourceNetworkId, tokenId) if (!token || !token.metadata) { return false diff --git a/packages/shared/src/lib/core/activity/utils/outputs/getFormattedAmountFromActivity.ts b/packages/shared/src/lib/core/activity/utils/outputs/getFormattedAmountFromActivity.ts index 19e5ba26b6..6d608a5d00 100644 --- a/packages/shared/src/lib/core/activity/utils/outputs/getFormattedAmountFromActivity.ts +++ b/packages/shared/src/lib/core/activity/utils/outputs/getFormattedAmountFromActivity.ts @@ -1,17 +1,19 @@ import { formatTokenAmountBestMatch } from '@core/token' import { ActivityAction, ActivityDirection } from '../../enums' import { getPersistedToken } from '@core/token/stores' +import { Activity } from '@core/activity/types' export function getFormattedAmountFromActivity( rawAmount: bigint, tokenId: string, - direction: ActivityDirection, - action: ActivityAction, + activity: Activity, signed: boolean = true ): string { - const metadata = getPersistedToken(tokenId)?.metadata + const metadata = getPersistedToken(activity.sourceNetworkId, tokenId)?.metadata const amount = metadata ? formatTokenAmountBestMatch(rawAmount, metadata) : '' return `${ - (direction === ActivityDirection.Outgoing || action === ActivityAction.Burn) && signed ? '- ' : '' + (activity.direction === ActivityDirection.Outgoing || activity.action === ActivityAction.Burn) && signed + ? '- ' + : '' }${amount}` } diff --git a/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts b/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts index 1c60281914..0ec9b33882 100644 --- a/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts +++ b/packages/shared/src/lib/core/layer-2/actions/canAccountMakeEvmTransaction.ts @@ -1,23 +1,22 @@ import { EvmNetworkId } from '@core/network/types' import { SendFlowType } from '@core/wallet/enums' - -import { getEvmChainGasPrice, getLayer2AccountBalanceForToken } from '../stores' - +import { getLayer2AccountBalanceForToken } from '../stores' import { FALLBACK_ESTIMATED_GAS, GAS_LIMIT_MULTIPLIER } from '../constants' import { calculateGasFeeInGlow } from '../helpers' +import { getEvmNetwork } from '@core/network' -export function canAccountMakeEvmTransaction( +export async function canAccountMakeEvmTransaction( accountIndex: number, networkId: EvmNetworkId, - sendFlowType: SendFlowType -): boolean | undefined { + sendFlowType: SendFlowType | undefined +): Promise { const baseTokenAccountBalance = getLayer2AccountBalanceForToken(accountIndex, networkId) const gasLimit = Math.floor( FALLBACK_ESTIMATED_GAS[sendFlowType ?? SendFlowType.BaseCoinTransfer] * GAS_LIMIT_MULTIPLIER ) - const gasPrice = getEvmChainGasPrice(networkId) + const gasPrice = await getEvmNetwork(networkId)?.getGasPrice() if (gasPrice === undefined) { - return undefined + return false } const minimumGasFee = calculateGasFeeInGlow(gasLimit, gasPrice) return baseTokenAccountBalance > minimumGasFee diff --git a/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts b/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts index 758584959b..7d6c2a98ec 100644 --- a/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts +++ b/packages/shared/src/lib/core/layer-2/actions/fetchL2BalanceForAccount.ts @@ -26,16 +26,20 @@ export function fetchL2BalanceForAccount(profileId: string, account: IAccountSta void updateErc721NftsOwnership(account, evmNetwork.id) } - const l2TokenBalance = isIscChain(evmNetwork) - ? await fetchIscAssetsForAccount(profileId, evmAddress, evmNetwork, account) - : {} + try { + const l2TokenBalance = isIscChain(evmNetwork) + ? await fetchIscAssetsForAccount(profileId, evmAddress, evmNetwork, account) + : {} - const erc20Balances = await getErc20BalancesForAddress(evmAddress, evmNetwork) - for (const [tokenId, balance] of Object.entries(erc20Balances)) { - await getOrRequestTokenFromPersistedTokens(tokenId, networkId) - l2TokenBalance[tokenId] = Number.isNaN(Number(balance)) ? BigInt(0) : balance + const erc20Balances = await getErc20BalancesForAddress(evmAddress, evmNetwork) + for (const [tokenId, balance] of Object.entries(erc20Balances)) { + await getOrRequestTokenFromPersistedTokens(tokenId, networkId) + l2TokenBalance[tokenId] = Number.isNaN(Number(balance)) ? BigInt(0) : balance + } + setLayer2AccountBalanceForChain(index, networkId, l2TokenBalance) + } catch (error) { + console.error(error) } - setLayer2AccountBalanceForChain(index, networkId, l2TokenBalance) }) } diff --git a/packages/shared/src/lib/core/layer-2/actions/getGasPriceForNetwork.ts b/packages/shared/src/lib/core/layer-2/actions/getGasPriceForNetwork.ts deleted file mode 100644 index d7fc7e2ba7..0000000000 --- a/packages/shared/src/lib/core/layer-2/actions/getGasPriceForNetwork.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { getEvmNetwork } from '@core/network' -import { EvmNetworkId } from '@core/network/types' -import { Converter } from '@core/utils' - -export async function getGasPriceForNetwork(networkId: EvmNetworkId): Promise { - const evmNetwork = getEvmNetwork(networkId) - if (!evmNetwork) { - return undefined - } - - const gasPrice = await evmNetwork.provider.eth.getGasPrice() - return Converter.decimalToHex(Number(gasPrice), true) -} diff --git a/packages/shared/src/lib/core/layer-2/actions/index.ts b/packages/shared/src/lib/core/layer-2/actions/index.ts index 4d26c39bbf..3e38a7a390 100644 --- a/packages/shared/src/lib/core/layer-2/actions/index.ts +++ b/packages/shared/src/lib/core/layer-2/actions/index.ts @@ -5,12 +5,9 @@ export * from './checkForUntrackedTokens' export * from './fetchL2BalanceForAccount' export * from './getGasFeeForLayer1ToLayer2Transaction' export * from './generateAndStoreEvmAddressForAccounts' -export * from './getGasPriceForNetwork' export * from './getIscTransferSmartContractData' export * from './getLayer2MetadataForTransfer' export * from './getLayer2NetworkFromAddress' export * from './getNetworkFromAddress' -export * from './pollEvmChainGasPrices' export * from './pollL2BalanceForAccount' export * from './setGasFee' -export * from './updateEvmChainGasPrice' diff --git a/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts b/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts deleted file mode 100644 index 630ca5534c..0000000000 --- a/packages/shared/src/lib/core/layer-2/actions/pollEvmChainGasPrices.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { EvmNetworkId } from '@core/network/types' -import { MILLISECONDS_PER_SECOND } from '@core/utils' -import { updateEvmChainGasPrice } from './updateEvmChainGasPrice' - -const EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL: number = 60 * MILLISECONDS_PER_SECOND - -const pollIntervalMap: { [id in EvmNetworkId]?: number } = {} - -export function pollEvmChainGasPrice(networkId: EvmNetworkId): void { - if (!networkId || isPollingEvmChainGasPrice(networkId)) { - return - } - void updateEvmChainGasPrice(networkId) - pollIntervalMap[networkId] = window.setInterval(() => { - void updateEvmChainGasPrice(networkId) - }, EVM_CHAIN_GAS_PRICE_POLLING_INTERVAL) -} - -export function pollEvmChainGasPrices(networkIds: EvmNetworkId[]): void { - stopPollingEvmChainGasPrices() - for (const networkId of networkIds) { - pollEvmChainGasPrice(networkId) - } -} - -export function stopPollingEvmChainGasPrices(networkIdsToIgnore?: EvmNetworkId[]): void { - for (const networkId of Object.keys(pollIntervalMap) as EvmNetworkId[]) { - if (!networkIdsToIgnore?.includes(networkId)) { - if (isPollingEvmChainGasPrice(networkId)) { - clearInterval(pollIntervalMap[networkId]) - } - } - } -} - -export function isPollingEvmChainGasPrice(networkId: EvmNetworkId): boolean { - return typeof pollIntervalMap[networkId] === 'number' -} diff --git a/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts b/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts deleted file mode 100644 index 0816471a16..0000000000 --- a/packages/shared/src/lib/core/layer-2/actions/updateEvmChainGasPrice.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { handleError } from '@core/error/handlers' -import { getEvmNetworks } from '@core/network/stores' -import { EvmNetworkId } from '@core/network/types' -import { setEvmChainGasPrice } from '../stores' -import { getGasPriceForNetwork } from './getGasPriceForNetwork' - -export async function updateEvmChainGasPrice(networkId: EvmNetworkId): Promise { - try { - const gasPrice = await getGasPriceForNetwork(networkId) - if (gasPrice) { - setEvmChainGasPrice(BigInt(gasPrice), networkId) - } - } catch (err) { - handleError(err) - } -} - -export async function updateEvmChainGasPrices(): Promise { - const networkIds = getEvmNetworks().map((evmNetwork) => evmNetwork.id) - await Promise.all(networkIds.map((networkId) => updateEvmChainGasPrice(networkId))) -} diff --git a/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts b/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts deleted file mode 100644 index 25227cc32b..0000000000 --- a/packages/shared/src/lib/core/layer-2/stores/evm-chain-gas-prices.store.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { get, writable } from 'svelte/store' -import { NetworkId } from '@core/network/types' -import { isEvmNetwork } from '@core/network/utils' -import { EvmChainGasPrices } from '../types' - -export const evmChainGasPrices = writable({}) - -export function getEvmChainGasPrice(networkId: NetworkId): bigint | undefined { - return get(evmChainGasPrices)[networkId] -} - -export function setEvmChainGasPrice(price: bigint, networkId: NetworkId): void { - evmChainGasPrices.update((state) => { - if (typeof price === 'bigint' && isEvmNetwork(networkId)) { - return { - ...state, - [networkId]: price, - } - } else { - return state - } - }) -} diff --git a/packages/shared/src/lib/core/layer-2/stores/index.ts b/packages/shared/src/lib/core/layer-2/stores/index.ts index 2c59ed1ce6..7c15aa4d3f 100644 --- a/packages/shared/src/lib/core/layer-2/stores/index.ts +++ b/packages/shared/src/lib/core/layer-2/stores/index.ts @@ -1,2 +1 @@ -export * from './evm-chain-gas-prices.store' export * from './layer2-balances.store' diff --git a/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts b/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts deleted file mode 100644 index 876a3c8e17..0000000000 --- a/packages/shared/src/lib/core/layer-2/types/evm-chain-gas-prices.type.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { NetworkId } from '@core/network/types' - -export type EvmChainGasPrices = { - [id in NetworkId]?: bigint -} diff --git a/packages/shared/src/lib/core/layer-2/types/index.ts b/packages/shared/src/lib/core/layer-2/types/index.ts index 9b525d20c3..797274a189 100644 --- a/packages/shared/src/lib/core/layer-2/types/index.ts +++ b/packages/shared/src/lib/core/layer-2/types/index.ts @@ -1,6 +1,5 @@ export * from './abi.type' export * from './contract.type' -export * from './evm-chain-gas-prices.type' export * from './evm-transaction-options.type' export * from './evm-transaction-data.type' export * from './layer-2-account-balance.type' diff --git a/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts b/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts index 631a6461ec..ce3ba22361 100644 --- a/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts +++ b/packages/shared/src/lib/core/network/classes/base-evm-network.class.ts @@ -10,6 +10,7 @@ import { EvmNetworkType, NetworkHealth, NetworkNamespace, ChainId } from '../enu import { IBlock, IEvmNetwork, IBaseEvmNetworkConfiguration } from '../interfaces' import { CoinType } from '@iota/sdk/out/types' import { EvmNetworkId, Web3Provider } from '../types' +import { IBaseToken } from '@core/token' import { NETWORK_STATUS_POLL_INTERVAL } from '@core/network/constants' export class BaseEvmNetwork implements IEvmNetwork { @@ -21,6 +22,7 @@ export class BaseEvmNetwork implements IEvmNetwork { public readonly type: EvmNetworkType public readonly coinType: CoinType public readonly name: string + public readonly baseToken: IBaseToken public readonly explorerUrl: string | undefined public readonly rpcEndpoint: string @@ -33,21 +35,24 @@ export class BaseEvmNetwork implements IEvmNetwork { chainId, type, coinType, + baseToken, name, explorerUrl, rpcEndpoint, }: IBaseEvmNetworkConfiguration) { try { - this.provider = new Web3(`${rpcEndpoint}`) + const _rpcEndpoint = new URL(rpcEndpoint).href + this.provider = new Web3(`${_rpcEndpoint}`) this.id = id this.namespace = namespace this.chainId = chainId this.type = type this.coinType = coinType + this.baseToken = baseToken this.name = name this.explorerUrl = explorerUrl - this.rpcEndpoint = rpcEndpoint + this.rpcEndpoint = _rpcEndpoint void this.startStatusPoll() } catch (err) { @@ -76,6 +81,15 @@ export class BaseEvmNetwork implements IEvmNetwork { return new this.provider.eth.Contract(abi, address) } + async getGasPrice(): Promise { + try { + const gasPrice = await this.provider.eth.getGasPrice() + return BigInt(gasPrice) + } catch { + return undefined + } + } + async getLatestBlock(): Promise { const number = await this.provider.eth.getBlockNumber() return this.provider.eth.getBlock(number) diff --git a/packages/shared/src/lib/core/network/classes/evm-network.class.ts b/packages/shared/src/lib/core/network/classes/evm-network.class.ts index d789879ef7..bb760d9c42 100644 --- a/packages/shared/src/lib/core/network/classes/evm-network.class.ts +++ b/packages/shared/src/lib/core/network/classes/evm-network.class.ts @@ -2,12 +2,9 @@ import { IPureEvmNetworkConfiguration } from '../interfaces' import { BaseEvmNetwork } from './base-evm-network.class' export class EvmNetwork extends BaseEvmNetwork { - public readonly symbol: string - constructor(chainConfiguration: IPureEvmNetworkConfiguration) { try { super(chainConfiguration) - this.symbol = chainConfiguration.symbol } catch (err) { console.error(err) throw new Error('Failed to construct isc Chain!') diff --git a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts index 7774f8fa0e..ddfe4f0508 100644 --- a/packages/shared/src/lib/core/network/classes/isc-chain.class.ts +++ b/packages/shared/src/lib/core/network/classes/isc-chain.class.ts @@ -13,13 +13,14 @@ export class IscChain extends BaseEvmNetwork { constructor(chainConfiguration: IIscChainConfiguration) { try { const { rpcEndpoint, aliasAddress, apiEndpoint } = chainConfiguration - const _rpcEndpoint = `${rpcEndpoint}/v1/chains/${aliasAddress}/evm` + const _rpcEndpoint = new URL(`v1/chains/${aliasAddress}/evm`, rpcEndpoint).href + super({ ...chainConfiguration, rpcEndpoint: _rpcEndpoint }) this.aliasAddress = aliasAddress this.apiEndpoint = apiEndpoint - this._chainApi = `${apiEndpoint}v1/chains/${aliasAddress}` + this._chainApi = new URL(`v1/chains/${aliasAddress}`, apiEndpoint).href } catch (err) { console.error(err) throw new Error('Failed to construct isc Chain!') diff --git a/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts b/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts index 66e1e9ed55..535dcb5a26 100644 --- a/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts +++ b/packages/shared/src/lib/core/network/constants/default-base-token.constant.ts @@ -3,7 +3,7 @@ import { IBaseToken } from '@core/token/interfaces' import { NetworkId } from '../types' import { SupportedNetworkId } from './supported-network-id.constant' -const DEFAULT_IOTA_BASE_TOKEN: IBaseToken = { +const IOTA_BASE_TOKEN: IBaseToken = { standard: TokenStandard.BaseToken, name: 'IOTA', tickerSymbol: 'IOTA', @@ -13,7 +13,7 @@ const DEFAULT_IOTA_BASE_TOKEN: IBaseToken = { useMetricPrefix: false, } -const DEFAULT_SHIMMER_BASE_TOKEN: IBaseToken = { +export const SHIMMER_BASE_TOKEN: IBaseToken = { standard: TokenStandard.BaseToken, name: 'Shimmer', tickerSymbol: 'SMR', @@ -23,20 +23,20 @@ const DEFAULT_SHIMMER_BASE_TOKEN: IBaseToken = { useMetricPrefix: false, } -const DEFAULT_TESTNET_BASE_TOKEN: IBaseToken = { +export const EVM_BASE_TOKEN: IBaseToken = { standard: TokenStandard.BaseToken, - name: 'Shimmer', - tickerSymbol: 'SMR', - unit: 'SMR', - decimals: 6, - subunit: 'glow', - useMetricPrefix: false, + name: 'Ether', + tickerSymbol: 'ETH', + unit: 'ETH', + decimals: 18, } export const DEFAULT_BASE_TOKEN: Readonly<{ [id in NetworkId]?: IBaseToken }> = { - [SupportedNetworkId.Iota]: DEFAULT_IOTA_BASE_TOKEN, - [SupportedNetworkId.Shimmer]: DEFAULT_SHIMMER_BASE_TOKEN, - [SupportedNetworkId.Testnet]: DEFAULT_TESTNET_BASE_TOKEN, - [SupportedNetworkId.ShimmerEvm]: DEFAULT_SHIMMER_BASE_TOKEN, - [SupportedNetworkId.TestnetEvm]: DEFAULT_TESTNET_BASE_TOKEN, + [SupportedNetworkId.Iota]: IOTA_BASE_TOKEN, + [SupportedNetworkId.Shimmer]: SHIMMER_BASE_TOKEN, + [SupportedNetworkId.Testnet]: SHIMMER_BASE_TOKEN, + [SupportedNetworkId.ShimmerEvm]: SHIMMER_BASE_TOKEN, + [SupportedNetworkId.TestnetEvm]: SHIMMER_BASE_TOKEN, + [SupportedNetworkId.Ethereum]: EVM_BASE_TOKEN, + [SupportedNetworkId.Sepolia]: EVM_BASE_TOKEN, } diff --git a/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts b/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts index 667d08170a..1df6486a9e 100644 --- a/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts +++ b/packages/shared/src/lib/core/network/constants/default-isc-chains-configurations.constant.ts @@ -1,6 +1,7 @@ import { EvmNetworkType, NetworkNamespace, ChainId } from '../enums' import { IIscChainConfiguration } from '../interfaces' import { StardustNetworkId } from '../types' +import { SHIMMER_BASE_TOKEN } from './default-base-token.constant' import { DEFAULT_COIN_TYPE } from './default-coin-type.constant' import { SupportedIscNetworkId, SupportedNetworkId, SupportedStardustNetworkId } from './supported-network-id.constant' @@ -11,6 +12,7 @@ export const DEFAULT_ISC_CHAINS_CONFIGURATIONS: Readonly<{ [id in StardustNetwor name: 'Shimmer EVM', chainId: ChainId.ShimmerEvm, namespace: NetworkNamespace.Evm, + baseToken: SHIMMER_BASE_TOKEN, coinType: DEFAULT_COIN_TYPE[SupportedNetworkId.ShimmerEvm] ?? 0, aliasAddress: 'smr1prxvwqvwf7nru5q5xvh5thwg54zsm2y4wfnk6yk56hj3exxkg92mx20wl3s', rpcEndpoint: 'https://json-rpc.evm.shimmer.network/', @@ -23,6 +25,7 @@ export const DEFAULT_ISC_CHAINS_CONFIGURATIONS: Readonly<{ [id in StardustNetwor name: 'Testnet EVM', chainId: ChainId.TestnetEvm, namespace: NetworkNamespace.Evm, + baseToken: SHIMMER_BASE_TOKEN, coinType: DEFAULT_COIN_TYPE[SupportedNetworkId.TestnetEvm] ?? 0, aliasAddress: 'rms1ppp00k5mmd2m8my8ukkp58nd3rskw6rx8l09aj35984k74uuc5u2cywn3ex', rpcEndpoint: 'https://json-rpc.evm.testnet.shimmer.network/', diff --git a/packages/shared/src/lib/core/network/constants/default-l1-evm-network-configurations.constant.ts b/packages/shared/src/lib/core/network/constants/default-l1-evm-network-configurations.constant.ts index df8f1844fd..63add616f2 100644 --- a/packages/shared/src/lib/core/network/constants/default-l1-evm-network-configurations.constant.ts +++ b/packages/shared/src/lib/core/network/constants/default-l1-evm-network-configurations.constant.ts @@ -4,6 +4,7 @@ import { EvmNetworkId } from '../types' import { DEFAULT_COIN_TYPE } from './default-coin-type.constant' import { SupportedL1EvmNetworkId, SupportedNetworkId } from './supported-network-id.constant' import { DEFAULT_EXPLORER_URLS } from './default-explorer-urls.constant' +import { EVM_BASE_TOKEN } from './default-base-token.constant' export const DEFAULT_L1_EVM_NETWORK_CONFIGURATION: Readonly<{ [key in EvmNetworkId]: IPureEvmNetworkConfiguration @@ -11,8 +12,7 @@ export const DEFAULT_L1_EVM_NETWORK_CONFIGURATION: Readonly<{ [SupportedL1EvmNetworkId.Ethereum]: { type: EvmNetworkType.PureEvm, name: 'Ethereum', - symbol: 'ETH', - ticker: 'ETH', + baseToken: EVM_BASE_TOKEN, id: SupportedL1EvmNetworkId.Ethereum, chainId: ChainId.Ethereum, namespace: NetworkNamespace.Evm, @@ -23,8 +23,7 @@ export const DEFAULT_L1_EVM_NETWORK_CONFIGURATION: Readonly<{ [SupportedL1EvmNetworkId.Sepolia]: { type: EvmNetworkType.PureEvm, name: 'Sepolia Testnet', - symbol: 'ETH', - ticker: 'ETH', + baseToken: EVM_BASE_TOKEN, id: SupportedL1EvmNetworkId.Sepolia, chainId: ChainId.Sepolia, namespace: NetworkNamespace.Evm, diff --git a/packages/shared/src/lib/core/network/interfaces/base-network.interface.ts b/packages/shared/src/lib/core/network/interfaces/base-network.interface.ts index ca06979358..af2a84607e 100644 --- a/packages/shared/src/lib/core/network/interfaces/base-network.interface.ts +++ b/packages/shared/src/lib/core/network/interfaces/base-network.interface.ts @@ -1,3 +1,4 @@ +import { IBaseToken } from '@core/token' import { Writable } from 'svelte/store' import { NetworkHealth, NetworkNamespace } from '../enums' import { NetworkId } from '../types' @@ -13,5 +14,6 @@ export interface IBaseNetworkMetadata { id: NetworkId namespace: NetworkNamespace name: string + baseToken: IBaseToken coinType: number } diff --git a/packages/shared/src/lib/core/network/interfaces/evm-network-configuration.interface.ts b/packages/shared/src/lib/core/network/interfaces/evm-network-configuration.interface.ts index 84a38f3ad8..2559632757 100644 --- a/packages/shared/src/lib/core/network/interfaces/evm-network-configuration.interface.ts +++ b/packages/shared/src/lib/core/network/interfaces/evm-network-configuration.interface.ts @@ -1,6 +1,7 @@ import { CoinType } from '@iota/sdk/out/types' import { EvmNetworkType, NetworkNamespace, ChainId } from '../enums' import { EvmNetworkId } from '../types' +import { IBaseToken } from '@core/token/interfaces' export interface IIscChainConfiguration extends IBaseEvmNetworkConfiguration { type: EvmNetworkType.Isc @@ -10,14 +11,13 @@ export interface IIscChainConfiguration extends IBaseEvmNetworkConfiguration { export interface IPureEvmNetworkConfiguration extends IBaseEvmNetworkConfiguration { type: EvmNetworkType.PureEvm - symbol: string - ticker: string } export interface IBaseEvmNetworkConfiguration { id: EvmNetworkId namespace: NetworkNamespace.Evm chainId: ChainId + baseToken: IBaseToken type: EvmNetworkType coinType: CoinType name: string diff --git a/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts b/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts index 80cd3df1ef..28c71ccf55 100644 --- a/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts +++ b/packages/shared/src/lib/core/network/interfaces/evm-network.interface.ts @@ -25,6 +25,8 @@ export interface IEvmNetwork extends IBaseNetwork, IBaseNetworkMetadata { provider: Web3Provider + getGasPrice(): Promise + getContract(type: ContractType, address: string): Contract getLatestBlock(): Promise } diff --git a/packages/shared/src/lib/core/network/interfaces/stardust-network-metadata.interface.ts b/packages/shared/src/lib/core/network/interfaces/stardust-network-metadata.interface.ts index 18b6a6664d..3b24d633c0 100644 --- a/packages/shared/src/lib/core/network/interfaces/stardust-network-metadata.interface.ts +++ b/packages/shared/src/lib/core/network/interfaces/stardust-network-metadata.interface.ts @@ -1,4 +1,3 @@ -import { IBaseToken } from '@core/token/interfaces' import { IProtocol } from './protocol.interface' import { StardustNetworkId } from '../types' import { NetworkNamespace } from '../enums' @@ -13,6 +12,5 @@ export interface IStardustNetworkMetadata extends IBaseNetworkMetadata { id: StardustNetworkId namespace: NetworkNamespace.Stardust protocol: IProtocol - baseToken: IBaseToken chainConfigurations: IIscChainConfiguration[] } diff --git a/packages/shared/src/lib/core/network/utils/canAccountMakeStardustTransaction.ts b/packages/shared/src/lib/core/network/utils/canAccountMakeStardustTransaction.ts index fb20ae08fc..2f9f87d92b 100644 --- a/packages/shared/src/lib/core/network/utils/canAccountMakeStardustTransaction.ts +++ b/packages/shared/src/lib/core/network/utils/canAccountMakeStardustTransaction.ts @@ -4,8 +4,8 @@ import { SendFlowType } from '@core/wallet/enums' export function canAccountMakeStardustTransaction( accountIndex: number, - sendFlowType: SendFlowType -): boolean | undefined { + sendFlowType: SendFlowType | undefined +): boolean { switch (sendFlowType) { case SendFlowType.BaseCoinTransfer: default: { @@ -14,7 +14,7 @@ export function canAccountMakeStardustTransaction( const baseTokenBalance = account?.balances.baseCoin return BigInt(baseTokenBalance?.available ?? 0) > BigInt(0) } else { - return undefined + return false } } } diff --git a/packages/shared/src/lib/core/nfts/actions/getPersistedErc721Nfts.ts b/packages/shared/src/lib/core/nfts/actions/getPersistedErc721NftsForNetwork.ts similarity index 59% rename from packages/shared/src/lib/core/nfts/actions/getPersistedErc721Nfts.ts rename to packages/shared/src/lib/core/nfts/actions/getPersistedErc721NftsForNetwork.ts index 5b83de8c32..db8a148913 100644 --- a/packages/shared/src/lib/core/nfts/actions/getPersistedErc721Nfts.ts +++ b/packages/shared/src/lib/core/nfts/actions/getPersistedErc721NftsForNetwork.ts @@ -3,12 +3,15 @@ import { getActiveProfile } from '@core/profile/stores' import { NftStandard } from '../enums' import { IPersistedErc721Nft } from '../interfaces' import { persistedNfts } from '../stores' +import { NetworkId } from '@core/network' -export function getPersistedErc721Nfts(): IPersistedErc721Nft[] { +export function getPersistedErc721NftsForNetwork(networkId: NetworkId): IPersistedErc721Nft[] { const activeProfileId = getActiveProfile()?.id if (activeProfileId) { const profileNfts = Object.values(get(persistedNfts)[activeProfileId] ?? {}) - return profileNfts.filter(({ standard }) => standard === NftStandard.Erc721) as IPersistedErc721Nft[] + return profileNfts.filter( + ({ standard, networkId: _networkId }) => standard === NftStandard.Erc721 && networkId === networkId + ) as IPersistedErc721Nft[] } else { throw new Error('Unable to get active profile') } diff --git a/packages/shared/src/lib/core/nfts/actions/index.ts b/packages/shared/src/lib/core/nfts/actions/index.ts index fc75891e32..7489b48b4f 100644 --- a/packages/shared/src/lib/core/nfts/actions/index.ts +++ b/packages/shared/src/lib/core/nfts/actions/index.ts @@ -4,7 +4,7 @@ export * from './buildNftFromNftOutput' export * from './checkForUntrackedNfts' export * from './downloadNextNftInQueue' export * from './getNftByIdFromAllAccountNfts' -export * from './getPersistedErc721Nfts' +export * from './getPersistedErc721NftsForNetwork' export * from './interruptNftDownloadAfterTimeout' export * from './isNftPersisted' export * from './loadNftsForActiveProfile' diff --git a/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts b/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts index 30e2a07751..5e0e46c9e8 100644 --- a/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts +++ b/packages/shared/src/lib/core/nfts/actions/loadNftsForActiveProfile.ts @@ -13,7 +13,7 @@ import { Nft } from '../interfaces' import { buildNftFromPersistedErc721Nft, getNftsFromNftIds } from '../utils' import { addNftsToDownloadQueue } from './addNftsToDownloadQueue' import { buildNftFromNftOutput } from './buildNftFromNftOutput' -import { getPersistedErc721Nfts } from './getPersistedErc721Nfts' +import { getPersistedErc721NftsForNetwork } from './getPersistedErc721NftsForNetwork' import { setAccountNftsInAllAccountNfts } from './setAccountNftsInAllAccountNfts' export async function loadNftsForActiveProfile(): Promise { @@ -70,7 +70,7 @@ export async function loadNftsForAccount(profileId: string, account: IAccountSta if (!evmAddress) { continue } - const erc721Nfts = getPersistedErc721Nfts() + const erc721Nfts = getPersistedErc721NftsForNetwork(evmNetwork.id) const convertedNfts: Nft[] = erc721Nfts.map((persistedErc721Nft) => buildNftFromPersistedErc721Nft(persistedErc721Nft, evmAddress) ) diff --git a/packages/shared/src/lib/core/profile/actions/active-profile/login.ts b/packages/shared/src/lib/core/profile/actions/active-profile/login.ts index e15d866799..44870af492 100644 --- a/packages/shared/src/lib/core/profile/actions/active-profile/login.ts +++ b/packages/shared/src/lib/core/profile/actions/active-profile/login.ts @@ -4,7 +4,6 @@ import { generateAndStoreActivitiesForAllAccounts } from '@core/activity/actions import { Platform } from '@core/app/classes' import { AppContext } from '@core/app/enums' import { handleError } from '@core/error/handlers' -import { updateEvmChainGasPrices } from '@core/layer-2/actions' import { fetchL2BalanceForAllAccounts } from '@core/layer-2/utils' import { pollLedgerDeviceState } from '@core/ledger/actions' import { pollMarketPrices } from '@core/market/actions' @@ -18,7 +17,7 @@ import { import { profileManager } from '@core/profile-manager/stores' import { buildProfileManagerOptionsFromProfileData } from '@core/profile-manager/utils' import { routerManager } from '@core/router/stores' -import { refreshAccountTokensForActiveProfile } from '@core/token/actions' +import { loadTokensForAllAccountBalances } from '@core/token/actions' import { SECONDS_PER_MINUTE } from '@core/utils' import { get } from 'svelte/store' import { ProfileType } from '../../enums' @@ -76,7 +75,7 @@ export async function login(loginOptions?: ILoginOptions): Promise { // Step 4: load assets incrementLoginProgress() - await refreshAccountTokensForActiveProfile(_activeProfile.forceAssetRefresh, _activeProfile.forceAssetRefresh) + await loadTokensForAllAccountBalances(_activeProfile.forceAssetRefresh, _activeProfile.forceAssetRefresh) updateActiveProfile({ forceAssetRefresh: false }) await loadNftsForActiveProfile() // checkAndRemoveProfilePicture() @@ -126,7 +125,6 @@ export async function login(loginOptions?: ILoginOptions): Promise { resetLoginProgress() }, 500) - void updateEvmChainGasPrices() void pollMarketPrices() void updateCirculatingSupplyForActiveProfile() if (Platform.isFeatureFlagEnabled('governance')) { diff --git a/packages/shared/src/lib/core/profile/constants/profile-version.constant.ts b/packages/shared/src/lib/core/profile/constants/profile-version.constant.ts index 15b74f935d..5213e73b0e 100644 --- a/packages/shared/src/lib/core/profile/constants/profile-version.constant.ts +++ b/packages/shared/src/lib/core/profile/constants/profile-version.constant.ts @@ -1,7 +1,7 @@ import { AppStage } from '@core/app/enums' export const PROFILE_VERSION: Record = { - [AppStage.ALPHA]: 16, + [AppStage.ALPHA]: 17, [AppStage.BETA]: 1, [AppStage.PROD]: 9, } diff --git a/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-15-to-16.ts b/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-15-to-16.ts index 0652080dbe..e892bb3820 100644 --- a/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-15-to-16.ts +++ b/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-15-to-16.ts @@ -15,6 +15,5 @@ export function alphaProfileMigration15To16(existingProfile: unknown): Promise { + const profile = existingProfile as IPersistedProfile + + profile.evmNetworks = (profile.evmNetworks ?? []).map((evmNetwork) => ({ + ...evmNetwork, + baseToken: DEFAULT_BASE_TOKEN[evmNetwork.id] as IBaseToken, + })) + + const updatedChainConfiguration = (profile.network.chainConfigurations ?? []).map((chain) => ({ + ...chain, + baseToken: DEFAULT_BASE_TOKEN[chain.id] as IBaseToken, + })) + + profile.network = { ...profile.network, chainConfigurations: updatedChainConfiguration } + + persistedTokens.update((state) => { + delete state[profile.id] + return state + }) + return Promise.resolve() +} diff --git a/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-map.ts b/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-map.ts index c33fa5f827..07e061c84a 100644 --- a/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-map.ts +++ b/packages/shared/src/lib/core/profile/migrations/alpha/alpha-profile-migration-map.ts @@ -7,6 +7,7 @@ import { alphaProfileMigration12To13 } from './alpha-profile-migration-12-to-13' import { alphaProfileMigration13To14 } from './alpha-profile-migration-13-to-14' import { alphaProfileMigration14To15 } from './alpha-profile-migration-14-to-15' import { alphaProfileMigration15To16 } from './alpha-profile-migration-15-to-16' +import { alphaProfileMigration16To17 } from './alpha-profile-migration-16-to-17' import { alphaProfileMigration2To3 } from './alpha-profile-migration-2-to-3' import { alphaProfileMigration3To4 } from './alpha-profile-migration-3-to-4' import { alphaProfileMigration4To5 } from './alpha-profile-migration-4-to-5' @@ -33,4 +34,5 @@ export const ALPHA_PROFILE_MIGRATION_MAP: ProfileMigrationMap = { 13: alphaProfileMigration13To14, 14: alphaProfileMigration14To15, 15: alphaProfileMigration15To16, + 16: alphaProfileMigration16To17, } diff --git a/packages/shared/src/lib/core/profile/migrations/prod/prod-profile-migration-8-to-9.ts b/packages/shared/src/lib/core/profile/migrations/prod/prod-profile-migration-8-to-9.ts index 47542982e6..eb69df554d 100644 --- a/packages/shared/src/lib/core/profile/migrations/prod/prod-profile-migration-8-to-9.ts +++ b/packages/shared/src/lib/core/profile/migrations/prod/prod-profile-migration-8-to-9.ts @@ -1,6 +1,9 @@ import { DappVerification } from '@auxiliary/wallet-connect/enums' import { persistDapp, persistedDappNamespaces } from '@auxiliary/wallet-connect/stores' +import { DEFAULT_BASE_TOKEN } from '@core/network/constants' import { IPersistedProfile } from '@core/profile/interfaces' +import { IBaseToken } from '@core/token/interfaces' +import { persistedTokens } from '@core/token/stores' import { get } from 'svelte/store' export function prodProfileMigration8To9(existingProfile: unknown): Promise { @@ -16,5 +19,14 @@ export function prodProfileMigration8To9(existingProfile: unknown): Promise ({ + ...evmNetwork, + baseToken: DEFAULT_BASE_TOKEN[evmNetwork.id] as IBaseToken, + })) + + persistedTokens.update((state) => { + delete state[profile.id] + return state + }) return Promise.resolve() } diff --git a/packages/shared/src/lib/core/token/actions/getAccountTokensForAccount.ts b/packages/shared/src/lib/core/token/actions/getAccountTokensForAccount.ts index 5c7c4cac2b..84202f4846 100644 --- a/packages/shared/src/lib/core/token/actions/getAccountTokensForAccount.ts +++ b/packages/shared/src/lib/core/token/actions/getAccountTokensForAccount.ts @@ -44,7 +44,7 @@ function getAccountAssetForNetwork( marketCurrency: MarketCurrency, networkId: StardustNetworkId ): IAccountTokensPerNetwork { - const persistedBaseCoin = getPersistedToken(BASE_TOKEN_ID) + const persistedBaseCoin = getPersistedToken(networkId, BASE_TOKEN_ID) const baseCoinMarketPrices = marketCoinPrices?.[persistedBaseCoin.metadata?.name?.toLowerCase() ?? ''] const baseCoinMarketPrice = String(baseCoinMarketPrices?.[marketCurrency]) const baseCoinTotal = account?.balances?.baseCoin?.total @@ -67,7 +67,7 @@ function getAccountAssetForNetwork( const nativeTokens: ITokenWithBalance[] = [] const tokens = account?.balances?.nativeTokens ?? [] for (const token of tokens) { - const persistedAsset = getPersistedToken(token.tokenId) + const persistedAsset = getPersistedToken(networkId, token.tokenId) if (persistedAsset && persistedAsset?.metadata && isValidIrc30Token(persistedAsset.metadata)) { nativeTokens.push({ ...persistedAsset, @@ -92,7 +92,7 @@ function getAccountAssetForChain( marketCurrency: MarketCurrency, networkId: EvmNetworkId ): IAccountTokensPerNetwork | undefined { - const persistedBaseCoin = getPersistedToken(BASE_TOKEN_ID) // we use the L1 coin type for now because we assume that the basecoin for L2 is SMR + const persistedBaseCoin = getPersistedToken(networkId, BASE_TOKEN_ID) const baseCoinMarketPrices = marketCoinPrices?.[persistedBaseCoin.metadata?.name?.toLowerCase() ?? ''] let baseCoin = createTokenWithBalanceFromPersistedAsset( persistedBaseCoin, @@ -119,7 +119,7 @@ function getAccountAssetForChain( networkId ) } else { - const persistedAsset = getPersistedToken(tokenId) + const persistedAsset = getPersistedToken(networkId, tokenId) if (persistedAsset && persistedAsset?.metadata && isValidToken(persistedAsset.metadata)) { const assetMarketPrices = marketCoinPrices?.[get(shimmerEvmAddressToCoinGeckoIdMap)?.[tokenId]] const nativeToken = createTokenWithBalanceFromPersistedAsset( diff --git a/packages/shared/src/lib/core/token/actions/getOrRequestTokenFromPersistedTokens.ts b/packages/shared/src/lib/core/token/actions/getOrRequestTokenFromPersistedTokens.ts index c722a0426d..e53ee2c8ed 100644 --- a/packages/shared/src/lib/core/token/actions/getOrRequestTokenFromPersistedTokens.ts +++ b/packages/shared/src/lib/core/token/actions/getOrRequestTokenFromPersistedTokens.ts @@ -8,13 +8,13 @@ export async function getOrRequestTokenFromPersistedTokens( networkId: NetworkId, persistTokenIfNotPresent = true ): Promise { - const persistedAsset = getPersistedToken(tokenId) + const persistedAsset = getPersistedToken(networkId, tokenId) if (persistedAsset) { return Promise.resolve(persistedAsset) } else { const tokenToPersist = await requestPersistedToken(tokenId, networkId) if (tokenToPersist && persistTokenIfNotPresent) { - addPersistedToken(tokenToPersist) + addPersistedToken(networkId, tokenToPersist) } return tokenToPersist } diff --git a/packages/shared/src/lib/core/token/actions/index.ts b/packages/shared/src/lib/core/token/actions/index.ts index 956ba1ceb3..c873bd05c3 100644 --- a/packages/shared/src/lib/core/token/actions/index.ts +++ b/packages/shared/src/lib/core/token/actions/index.ts @@ -2,6 +2,6 @@ export * from './getAccountTokensForAccount' export * from './getOrRequestTokenFromPersistedTokens' export * from './getTokenBalance' export * from './isVisibleToken' -export * from './refreshAccountTokensForActiveProfile' +export * from './loadTokensForAllAccountBalances' export * from './removeTrackedTokenFromActiveProfile' export * from './requestPersistedToken' diff --git a/packages/shared/src/lib/core/token/actions/loadTokensForAllAccountBalances.ts b/packages/shared/src/lib/core/token/actions/loadTokensForAllAccountBalances.ts new file mode 100644 index 0000000000..6ee02b453c --- /dev/null +++ b/packages/shared/src/lib/core/token/actions/loadTokensForAllAccountBalances.ts @@ -0,0 +1,118 @@ +import { IEvmNetwork, IStardustNetwork, NetworkId, getEvmNetworks, getL1Network } from '@core/network' +import { activeAccounts, activeProfile } from '@core/profile/stores' +import { get } from 'svelte/store' +import { getOrRequestTokenFromPersistedTokens } from '.' +import { BASE_TOKEN_ID } from '../constants' +import { TokenStandard, VerifiedStatus } from '../enums' +import { IPersistedToken } from '../interfaces' +import { + addPersistedToken, + clearPersistedTokensForActiveProfile, + persistedTokens, +} from '../stores/persisted-tokens.store' +import { TokenVerification } from '../types' +import { getLayer2AccountBalance } from '@core/layer-2/stores' + +export async function loadTokensForAllAccountBalances( + clearPersistedAssets = false, + keepVerificationStatus = false +): Promise { + clearPersistedAssets && clearPersistedTokensForActiveProfile() + + const tokens: { [networkId: NetworkId]: IPersistedToken[] } = {} + const l1StardustNetwork = getL1Network() + const stardustTokens = await loadTokensForStardustNetwork(l1StardustNetwork, keepVerificationStatus) + tokens[l1StardustNetwork.id] = stardustTokens + + for (const network of getEvmNetworks()) { + const evmTokens = await loadTokensForEvmNetwork(network, keepVerificationStatus) + tokens[network.id] = evmTokens + } + + for (const [networkId, assets] of Object.entries(tokens)) { + addPersistedToken(networkId as NetworkId, ...assets) + } +} + +async function loadTokensForStardustNetwork( + network: IStardustNetwork, + keepVerificationStatus: boolean +): Promise { + const storedVerificationStates: { [tokenId: string]: TokenVerification } = keepVerificationStatus + ? getPersistedVerificationStatesForNetwork(network.id) + : {} + + const baseCoin: IPersistedToken = { + id: BASE_TOKEN_ID, + standard: TokenStandard.BaseToken, + metadata: network.baseToken, + hidden: false, + verification: { verified: true, status: VerifiedStatus.Official }, + } + + const tokens: IPersistedToken[] = [] + const accounts = get(activeAccounts) + for (const account of accounts) { + const tokenBalances = account?.balances?.nativeTokens ?? [] + for (const tokenBalance of tokenBalances) { + try { + const token = await getOrRequestTokenFromPersistedTokens(tokenBalance.tokenId, network.id, false) + if (token) { + tokens.push({ + ...token, + verification: storedVerificationStates[token.id] ?? token.verification, + }) + } + } catch (err) { + console.error(err) + } + } + } + return [baseCoin, ...tokens] +} + +async function loadTokensForEvmNetwork( + network: IEvmNetwork, + keepVerificationStatus: boolean +): Promise { + const storedVerificationStates: { [tokenId: string]: TokenVerification } = keepVerificationStatus + ? getPersistedVerificationStatesForNetwork(network.id) + : {} + + const baseCoin: IPersistedToken = { + id: BASE_TOKEN_ID, + standard: TokenStandard.BaseToken, + metadata: network.baseToken, + hidden: false, + verification: { verified: true, status: VerifiedStatus.Official }, + } + + const tokens: IPersistedToken[] = [] + const accounts = get(activeAccounts) + for (const account of accounts) { + const tokenBalances = getLayer2AccountBalance(account.index)?.[network.id] ?? {} + for (const tokenId of Object.keys(tokenBalances)) { + try { + const token = await getOrRequestTokenFromPersistedTokens(tokenId, network.id, false) + if (token) { + tokens.push({ + ...token, + verification: storedVerificationStates[token.id] ?? token.verification, + }) + } + } catch (err) { + console.error(err) + } + } + } + return [baseCoin, ...tokens] +} + +function getPersistedVerificationStatesForNetwork(networkId: NetworkId): { [tokenId: string]: TokenVerification } { + const assets = get(persistedTokens)?.[get(activeProfile)?.id]?.[networkId] ?? {} + const verificationStates: { [tokenId: string]: TokenVerification } = {} + for (const [id, asset] of Object.entries(assets)) { + verificationStates[id] = asset.verification + } + return verificationStates +} diff --git a/packages/shared/src/lib/core/token/actions/refreshAccountTokensForActiveProfile.ts b/packages/shared/src/lib/core/token/actions/refreshAccountTokensForActiveProfile.ts deleted file mode 100644 index 4e49e1976e..0000000000 --- a/packages/shared/src/lib/core/token/actions/refreshAccountTokensForActiveProfile.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { getActiveNetworkId } from '@core/network' -import { getBaseToken } from '@core/profile/actions' -import { activeAccounts, activeProfile } from '@core/profile/stores' -import { get } from 'svelte/store' -import { getOrRequestTokenFromPersistedTokens } from '../actions' -import { BASE_TOKEN_ID } from '../constants' -import { TokenStandard, VerifiedStatus } from '../enums' -import { IPersistedToken } from '../interfaces' -import { - addPersistedToken, - clearPersistedTokensForActiveProfile, - persistedTokens, -} from '../stores/persisted-tokens.store' - -export async function refreshAccountTokensForActiveProfile( - clearPersistedAssets = false, - keepVerificationStatus = false -): Promise { - const storedVerificationStates = {} - if (keepVerificationStatus) { - const assets = get(persistedTokens)?.[get(activeProfile)?.id] ?? {} - for (const [id, asset] of Object.entries(assets)) { - storedVerificationStates[id] = asset.verification - } - } - clearPersistedAssets && clearPersistedTokensForActiveProfile() - - const persistedBaseCoin: IPersistedToken = { - id: BASE_TOKEN_ID, - standard: TokenStandard.BaseToken, - metadata: getBaseToken(), - hidden: false, - verification: { verified: true, status: VerifiedStatus.Official }, - } - - const assets: IPersistedToken[] = [] - const accounts = get(activeAccounts) - for (const account of accounts) { - const tokens = account?.balances?.nativeTokens ?? [] - for (const token of tokens) { - try { - const persistedAsset = await getOrRequestTokenFromPersistedTokens( - token.tokenId, - getActiveNetworkId(), - false - ) - if (persistedAsset) { - if (keepVerificationStatus) { - const verificationStatus = storedVerificationStates[persistedAsset.id] - persistedAsset.verification = verificationStatus - } - assets.push(persistedAsset) - } - } catch (err) { - console.error(err) - } - } - } - addPersistedToken(persistedBaseCoin, ...assets) -} diff --git a/packages/shared/src/lib/core/token/interfaces/account-tokens.interface.ts b/packages/shared/src/lib/core/token/interfaces/account-tokens.interface.ts index 410ffc4ebe..a1a4eb1ade 100644 --- a/packages/shared/src/lib/core/token/interfaces/account-tokens.interface.ts +++ b/packages/shared/src/lib/core/token/interfaces/account-tokens.interface.ts @@ -6,6 +6,6 @@ export type AccountTokens = { } export interface IAccountTokensPerNetwork { - baseCoin: ITokenWithBalance | undefined + baseCoin: ITokenWithBalance nativeTokens: ITokenWithBalance[] } diff --git a/packages/shared/src/lib/core/token/interfaces/persisted-tokens.interface.ts b/packages/shared/src/lib/core/token/interfaces/persisted-tokens.interface.ts index 90ccd40c0b..e4a8597f3b 100644 --- a/packages/shared/src/lib/core/token/interfaces/persisted-tokens.interface.ts +++ b/packages/shared/src/lib/core/token/interfaces/persisted-tokens.interface.ts @@ -1,7 +1,10 @@ +import { NetworkId } from '@core/network/types' import { IPersistedToken } from './persisted-token.interface' export interface IPersistedTokens { [profileId: string]: { - [tokenId: string]: IPersistedToken + [networkId: NetworkId]: { + [tokenId: string]: IPersistedToken + } } } diff --git a/packages/shared/src/lib/core/token/stores/persisted-tokens.store.ts b/packages/shared/src/lib/core/token/stores/persisted-tokens.store.ts index 6897927aeb..022832f07f 100644 --- a/packages/shared/src/lib/core/token/stores/persisted-tokens.store.ts +++ b/packages/shared/src/lib/core/token/stores/persisted-tokens.store.ts @@ -1,58 +1,53 @@ -import { activeProfileId } from '@core/profile/stores/active-profile-id.store' -import { activeProfile } from '@core/profile/stores/active-profile.store' +import { getActiveProfileId } from '@core/profile/stores/active-profile-id.store' import { persistent } from '@core/utils/store' import { get } from 'svelte/store' import { NotVerifiedStatus, VerifiedStatus } from '../enums' -import { IPersistedToken, IPersistedTokens } from '../interfaces' +import { IPersistedToken, IPersistedTokens, IToken } from '../interfaces' +import { NetworkId } from '@core/network/types' export const persistedTokens = persistent('persistedTokens', {}) -export function getPersistedToken(tokenId: string): IPersistedToken { - return get(persistedTokens)?.[get(activeProfile)?.id]?.[tokenId] +export function getPersistedToken(networkId: NetworkId, tokenId: string): IPersistedToken { + const profileId = getActiveProfileId() + return get(persistedTokens)?.[profileId]?.[networkId]?.[tokenId] } -export function addPersistedToken(...newPersistedTokens: IPersistedToken[]): void { +export function addPersistedToken(networkId: NetworkId, ...newPersistedTokens: IPersistedToken[]): void { + const profileId = getActiveProfileId() persistedTokens.update((state) => { - if (!state[get(activeProfile).id]) { - state[get(activeProfile).id] = {} + if (!state[profileId]) { + state[profileId] = {} + } + if (!state[profileId][networkId]) { + state[profileId][networkId] = {} } for (const token of newPersistedTokens) { - state[get(activeProfile).id][token.id] = token + state[profileId][networkId][token.id] = token } return state }) } export function clearPersistedTokensForActiveProfile(): void { + const profileId = getActiveProfileId() persistedTokens.update((state) => { - state[get(activeProfile).id] = {} + state[profileId] = {} return state }) } -export function updatePersistedToken(partialPersistedToken: Partial): void { +export function updatePersistedToken(networkId: NetworkId, partialPersistedToken: Partial): void { + const profileId = getActiveProfileId() const tokenId = partialPersistedToken?.id - if (tokenId) { - persistedTokens.update((state) => { - state[get(activeProfile).id][tokenId] = { - ...state[get(activeProfile).id][tokenId], - ...partialPersistedToken, - } + persistedTokens.update((state) => { + if (!tokenId || state[profileId]?.[networkId]?.[tokenId] === undefined) { return state - }) - } -} - -export function removePersistedToken(tokenId: string): void { - const profileId = get(activeProfileId) - if (!profileId) { - return - } - persistedTokens.update((_persistedTokens) => { - if (_persistedTokens?.[profileId]?.[tokenId]) { - delete _persistedTokens[profileId][tokenId] } - return _persistedTokens + state[profileId][networkId][tokenId] = { + ...state[profileId][networkId][tokenId], + ...partialPersistedToken, + } + return state }) } @@ -63,18 +58,18 @@ export function removePersistedTokensForProfile(profileId: string): void { }) } -export function verifyToken(tokenId: string, status: VerifiedStatus): void { - updatePersistedToken({ id: tokenId, verification: { verified: true, status } }) +export function verifyToken(token: IToken, status: VerifiedStatus): void { + updatePersistedToken(token.networkId, { id: token.id, verification: { verified: true, status } }) } -export function unverifyToken(tokenId: string, status: NotVerifiedStatus): void { - updatePersistedToken({ id: tokenId, verification: { verified: false, status } }) +export function unverifyToken(token: IToken, status: NotVerifiedStatus): void { + updatePersistedToken(token.networkId, { id: token.id, verification: { verified: false, status } }) } -export function hideToken(tokenId: string): void { - updatePersistedToken({ id: tokenId, hidden: true }) +export function hideToken(token: IToken): void { + updatePersistedToken(token.networkId, { id: token.id, hidden: true }) } -export function unhideToken(tokenId: string): void { - updatePersistedToken({ id: tokenId, hidden: false }) +export function unhideToken(token: IToken): void { + updatePersistedToken(token.networkId, { id: token.id, hidden: false }) } diff --git a/packages/shared/src/lib/core/token/stores/selected-account-tokens.store.ts b/packages/shared/src/lib/core/token/stores/selected-account-tokens.store.ts index 2fd27b78d4..6d962981f6 100644 --- a/packages/shared/src/lib/core/token/stores/selected-account-tokens.store.ts +++ b/packages/shared/src/lib/core/token/stores/selected-account-tokens.store.ts @@ -78,11 +78,14 @@ export const visibleSelectedAccountTokens: Readable = derived( const visibleTokens: AccountTokens = {} for (const _networkId of Object.keys($selectedAccountTokens)) { const networkId = _networkId as NetworkId - const visible: IAccountTokensPerNetwork = { - baseCoin: $selectedAccountTokens[networkId]?.baseCoin, - nativeTokens: $selectedAccountTokens[networkId]?.nativeTokens.filter((asset) => !asset.hidden) ?? [], + const tokens = $selectedAccountTokens[networkId] + if (tokens) { + const visible: IAccountTokensPerNetwork = { + baseCoin: tokens.baseCoin, + nativeTokens: tokens.nativeTokens.filter((asset) => !asset.hidden) ?? [], + } + visibleTokens[networkId] = visible } - visibleTokens[networkId] = visible } return visibleTokens } @@ -101,7 +104,7 @@ export function getTokenFromSelectedAccountTokens( if (token) { return token } else { - const persistedToken = getPersistedToken(tokenId) + const persistedToken = getPersistedToken(networkId, tokenId) return persistedToken ? { ...persistedToken, diff --git a/packages/shared/src/lib/core/wallet/actions/addNewTrackedTokenToActiveProfile.ts b/packages/shared/src/lib/core/wallet/actions/addNewTrackedTokenToActiveProfile.ts index 01a933e5be..16cb84ce44 100644 --- a/packages/shared/src/lib/core/wallet/actions/addNewTrackedTokenToActiveProfile.ts +++ b/packages/shared/src/lib/core/wallet/actions/addNewTrackedTokenToActiveProfile.ts @@ -22,7 +22,7 @@ export function addNewTrackedTokenToActiveProfile( trackedTokens[tokenAddress] = tokenTrackingStatus profile.trackedTokens = { ...trackedTokensOnProfile, [networkId]: trackedTokens } - updatePersistedToken(buildPersistedTokenFromMetadata(tokenAddress, tokenMetadata)) + updatePersistedToken(networkId, buildPersistedTokenFromMetadata(tokenAddress, tokenMetadata)) updateActiveProfile(profile) } } diff --git a/packages/shared/src/lib/core/wallet/actions/mintNativeToken.ts b/packages/shared/src/lib/core/wallet/actions/mintNativeToken.ts index 26c38f537a..25f83d2a1d 100644 --- a/packages/shared/src/lib/core/wallet/actions/mintNativeToken.ts +++ b/packages/shared/src/lib/core/wallet/actions/mintNativeToken.ts @@ -37,7 +37,7 @@ export async function mintNativeToken( verified: true, status: VerifiedStatus.SelfVerified, }) - addPersistedToken(persistedAsset) + addPersistedToken(networkId, persistedAsset) await processAndAddToActivities(transaction, account, networkId) diff --git a/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts b/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts index 2e131302ea..4d701d3538 100644 --- a/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts +++ b/packages/shared/src/lib/core/wallet/tests/getOutputParameters.test.ts @@ -96,10 +96,6 @@ jest.mock('../../network/stores/networks.store', () => ({ getIscChain: jest.fn((_) => destinationNetwork), })) -jest.mock('../../layer-2/actions/getGasPriceForNetwork', () => ({ - getGasPriceForNetwork: jest.fn((_) => 1_000_000_000_000n), -})) - jest.mock('../../layer-2/actions/getGasFeeForLayer1ToLayer2Transaction', () => ({ getGasFeeForLayer1ToLayer2Transaction: jest.fn(({ type }) => FALLBACK_ESTIMATED_GAS[type]), }))