diff --git a/.changeset/tender-walls-hope.md b/.changeset/tender-walls-hope.md new file mode 100644 index 0000000000..c360fd35f4 --- /dev/null +++ b/.changeset/tender-walls-hope.md @@ -0,0 +1,5 @@ +--- +'alephium-desktop-wallet': patch +--- + +Fix display of NFT when minting diff --git a/.changeset/whole-aliens-double.md b/.changeset/whole-aliens-double.md new file mode 100644 index 0000000000..a471fa6013 --- /dev/null +++ b/.changeset/whole-aliens-double.md @@ -0,0 +1,5 @@ +--- +'@alephium/mobile-wallet': patch +--- + +Fix display of NFT when minting diff --git a/apps/desktop-wallet/src/components/TokenAmountsBox.tsx b/apps/desktop-wallet/src/components/TokenAmountsBox.tsx index 0e36897172..fda2851e99 100644 --- a/apps/desktop-wallet/src/components/TokenAmountsBox.tsx +++ b/apps/desktop-wallet/src/components/TokenAmountsBox.tsx @@ -90,6 +90,7 @@ interface AssetAmountRowProps extends AmountBaseProps { tokenId: string amount: string extraAlphForDust: bigint + skipCaching?: boolean } const AssetAmountRow = ({ tokenId, amount, extraAlphForDust, ...props }: AssetAmountRowProps) => { diff --git a/apps/desktop-wallet/src/features/transactionsDisplay/TransactionSummary.tsx b/apps/desktop-wallet/src/features/transactionsDisplay/TransactionSummary.tsx index 5267a24be0..17430c9902 100644 --- a/apps/desktop-wallet/src/features/transactionsDisplay/TransactionSummary.tsx +++ b/apps/desktop-wallet/src/features/transactionsDisplay/TransactionSummary.tsx @@ -7,13 +7,14 @@ import { TransactionDisplayProps } from '@/features/transactionsDisplay/transact interface TransactionSummaryProps extends TransactionDisplayProps { hideType?: boolean className?: string + skipCaching?: boolean } -const TransactionSummary = ({ tx, referenceAddress, hideType, className }: TransactionSummaryProps) => ( +const TransactionSummary = ({ tx, referenceAddress, hideType, className, skipCaching }: TransactionSummaryProps) => ( {!hideType && } - + ) diff --git a/apps/desktop-wallet/src/features/transactionsDisplay/transactionDetailsModal/TransactionAmounts.tsx b/apps/desktop-wallet/src/features/transactionsDisplay/transactionDetailsModal/TransactionAmounts.tsx index 0dee6da8c7..877c36643c 100644 --- a/apps/desktop-wallet/src/features/transactionsDisplay/transactionDetailsModal/TransactionAmounts.tsx +++ b/apps/desktop-wallet/src/features/transactionsDisplay/transactionDetailsModal/TransactionAmounts.tsx @@ -1,16 +1,20 @@ -import { useTransactionAmountDeltas, useTransactionInfoType } from '@alephium/shared-react' +import { NOCACHE_PREFIX, useTransactionAmountDeltas, useTransactionInfoType } from '@alephium/shared-react' import { ALPH } from '@alephium/token-list' import { useMemo } from 'react' import TokenAmountsBox from '@/components/TokenAmountsBox' import { TransactionDisplayProps } from '@/features/transactionsDisplay/transactionDisplayTypes' -const TransactionAmounts = ({ tx, referenceAddress }: TransactionDisplayProps) => { +const TransactionAmounts = ({ + tx, + referenceAddress, + skipCaching +}: TransactionDisplayProps & { skipCaching?: boolean }) => { const { alphAmount, tokenAmounts } = useTransactionAmountDeltas(tx, referenceAddress) - const assetAmounts = useMemo( - () => (alphAmount !== BigInt(0) ? [{ id: ALPH.id, amount: alphAmount }, ...tokenAmounts] : tokenAmounts), - [alphAmount, tokenAmounts] - ) + const assetAmounts = useMemo(() => { + const _tokenAmounts = tokenAmounts.map((t) => ({ ...t, id: skipCaching ? `${NOCACHE_PREFIX}${t.id}` : t.id })) + return alphAmount !== BigInt(0) ? [{ id: ALPH.id, amount: alphAmount }, ..._tokenAmounts] : _tokenAmounts + }, [alphAmount, skipCaching, tokenAmounts]) const infoType = useTransactionInfoType({ tx, referenceAddress: referenceAddress, view: 'wallet' }) diff --git a/apps/desktop-wallet/src/features/walletConnect/SignExecuteScriptTxModal.tsx b/apps/desktop-wallet/src/features/walletConnect/SignExecuteScriptTxModal.tsx index f1b2bc8293..cef57e5780 100644 --- a/apps/desktop-wallet/src/features/walletConnect/SignExecuteScriptTxModal.tsx +++ b/apps/desktop-wallet/src/features/walletConnect/SignExecuteScriptTxModal.tsx @@ -120,7 +120,7 @@ const SimulatedResult = ({ {t('Simulated result')} {isRelevant ? ( <> - + diff --git a/apps/mobile-wallet/src/features/ecosystem/modals/SignExecuteScriptTxModal.tsx b/apps/mobile-wallet/src/features/ecosystem/modals/SignExecuteScriptTxModal.tsx index 8d1745eefe..dc62cf34a1 100644 --- a/apps/mobile-wallet/src/features/ecosystem/modals/SignExecuteScriptTxModal.tsx +++ b/apps/mobile-wallet/src/features/ecosystem/modals/SignExecuteScriptTxModal.tsx @@ -152,7 +152,7 @@ const SimulatedResult = ({ /> )} - + ) : ( diff --git a/apps/mobile-wallet/src/features/transactionsDisplay/TransactionModal.tsx b/apps/mobile-wallet/src/features/transactionsDisplay/TransactionModal.tsx index bb914b5776..799d479a15 100644 --- a/apps/mobile-wallet/src/features/transactionsDisplay/TransactionModal.tsx +++ b/apps/mobile-wallet/src/features/transactionsDisplay/TransactionModal.tsx @@ -193,15 +193,16 @@ const TransactionStatus = ({ tx }: Pick interface TransactionAmountsProps extends TransactionModalSubcomponentProps { isLast?: boolean + skipCaching?: boolean } -export const TransactionAmounts = ({ tx, referenceAddress, isLast }: TransactionAmountsProps) => { +export const TransactionAmounts = ({ tx, referenceAddress, isLast, skipCaching }: TransactionAmountsProps) => { const { t } = useTranslation() const theme = useTheme() const dispatch = useAppDispatch() const { data: { fungibleTokens, nfts, nsts } - } = useFetchTransactionTokens(tx, referenceAddress) + } = useFetchTransactionTokens(tx, referenceAddress, skipCaching) const infoType = useTransactionInfoType({ tx, referenceAddress, view: 'wallet' }) const groupedFtAmounts = useMemo( diff --git a/packages/shared-react/src/api/apiDataHooks/token/useFetchToken.ts b/packages/shared-react/src/api/apiDataHooks/token/useFetchToken.ts index c5b4a8f2ae..9315c6cbc1 100644 --- a/packages/shared-react/src/api/apiDataHooks/token/useFetchToken.ts +++ b/packages/shared-react/src/api/apiDataHooks/token/useFetchToken.ts @@ -4,10 +4,10 @@ import { useQuery } from '@tanstack/react-query' import { tokenQuery } from '@/api/queries/tokenQueries' import { useCurrentlyOnlineNetworkId } from '@/network' -export const useFetchToken = (id: TokenId) => { +export const useFetchToken = (id: TokenId, skipCaching?: boolean) => { const networkId = useCurrentlyOnlineNetworkId() - const { data, isLoading } = useQuery(tokenQuery({ id, networkId })) + const { data, isLoading } = useQuery(tokenQuery({ id, networkId, skipCaching })) return { data, diff --git a/packages/shared-react/src/api/apiDataHooks/transaction/useFetchTransactionTokens.ts b/packages/shared-react/src/api/apiDataHooks/transaction/useFetchTransactionTokens.ts index 1a3b834af4..a0c45e63bd 100644 --- a/packages/shared-react/src/api/apiDataHooks/transaction/useFetchTransactionTokens.ts +++ b/packages/shared-react/src/api/apiDataHooks/transaction/useFetchTransactionTokens.ts @@ -37,13 +37,14 @@ type TransactionTokens = { export const useFetchTransactionTokens = ( tx: e.Transaction | e.PendingTransaction | SentTransaction | ExecuteScriptTx, - addressHash: AddressHash + addressHash: AddressHash, + skipCaching: boolean = false ): TransactionTokens => { const networkId = useCurrentlyOnlineNetworkId() const { alphAmount, tokenAmounts } = useTransactionAmountDeltas(tx, addressHash) const { data: tokens, isLoading } = useQueries({ - queries: tokenAmounts.map(({ id }) => tokenQuery({ id, networkId })), + queries: tokenAmounts.map(({ id }) => tokenQuery({ id, networkId, skipCaching })), combine: (results) => combineTokens(results, tokenAmounts) }) diff --git a/packages/shared-react/src/api/apiUtils.ts b/packages/shared-react/src/api/apiUtils.ts index fbab76848b..76b73293b7 100644 --- a/packages/shared-react/src/api/apiUtils.ts +++ b/packages/shared-react/src/api/apiUtils.ts @@ -2,6 +2,7 @@ import { AddressWithGroup, getMissingBalancesChainedTxParams, getTransactionExpectedBalances, + ONE_MINUTE_MS, TokenId, TransactionParams, UnlistedFT @@ -16,11 +17,12 @@ interface GetQueryConfigProps { gcTime: number staleTime?: number networkId?: number + skipCaching?: boolean } -export const getQueryConfig = ({ staleTime, gcTime, networkId }: GetQueryConfigProps) => ({ - staleTime, - gcTime, +export const getQueryConfig = ({ staleTime, gcTime, networkId, skipCaching }: GetQueryConfigProps) => ({ + staleTime: skipCaching ? 0 : staleTime, + gcTime: skipCaching ? ONE_MINUTE_MS : gcTime, meta: { isMainnet: networkId === 0 } }) diff --git a/packages/shared-react/src/api/queries/tokenQueries.ts b/packages/shared-react/src/api/queries/tokenQueries.ts index c3de2e1486..c87095fcfd 100644 --- a/packages/shared-react/src/api/queries/tokenQueries.ts +++ b/packages/shared-react/src/api/queries/tokenQueries.ts @@ -28,6 +28,7 @@ export const StdInterfaceIds = Object.values(e.TokenStdInterfaceId) interface TokenQueryProps extends SkipProp { id: TokenId networkId?: number + skipCaching?: boolean } interface NFTQueryProps extends TokenQueryProps { @@ -82,12 +83,12 @@ export const ftListQuery = ({ networkId, skip }: Omit) => }) } -export const tokenTypeQuery = ({ id, networkId, skip }: TokenQueryProps) => +export const tokenTypeQuery = ({ id, networkId, skip, skipCaching }: TokenQueryProps) => queryOptions({ - queryKey: ['token', 'type', id], + queryKey: ['token', 'type', getId(id, skipCaching)], // We always want to remember the type of a token, even when user navigates for too long from components that use // tokens. - ...getQueryConfig({ staleTime: Infinity, gcTime: Infinity, networkId }), + ...getQueryConfig({ staleTime: Infinity, gcTime: Infinity, networkId, skipCaching }), queryFn: !skip && networkId !== undefined ? async () => { @@ -127,10 +128,10 @@ export const combineTokenTypes = (tokenTypes: (e.TokenInfo | { data: e.TokenInfo } as Record ) -export const fungibleTokenMetadataQuery = ({ id, networkId, skip }: TokenQueryProps) => +export const fungibleTokenMetadataQuery = ({ id, networkId, skip, skipCaching }: TokenQueryProps) => queryOptions({ - queryKey: ['token', 'fungible', 'metadata', id], - ...getQueryConfig({ staleTime: Infinity, gcTime: Infinity, networkId }), + queryKey: ['token', 'fungible', 'metadata', getId(id, skipCaching)], + ...getQueryConfig({ staleTime: Infinity, gcTime: Infinity, networkId, skipCaching }), queryFn: !skip ? async () => { const tokenMetadata = await batchers.ftMetadataBatcher.fetch(id) @@ -140,18 +141,18 @@ export const fungibleTokenMetadataQuery = ({ id, networkId, skip }: TokenQueryPr : skipToken }) -export const nftMetadataQuery = ({ id, networkId, skip }: TokenQueryProps) => +export const nftMetadataQuery = ({ id, networkId, skip, skipCaching }: TokenQueryProps) => queryOptions({ - queryKey: ['token', 'non-fungible', 'metadata', id], - ...getQueryConfig({ staleTime: Infinity, gcTime: Infinity, networkId }), + queryKey: ['token', 'non-fungible', 'metadata', getId(id, skipCaching)], + ...getQueryConfig({ staleTime: Infinity, gcTime: Infinity, networkId, skipCaching }), queryFn: !skip ? async () => (await batchers.nftMetadataBatcher.fetch(id)) ?? null : skipToken }) -export const nftDataQuery = ({ id, tokenUri, networkId, skip }: NFTQueryProps) => +export const nftDataQuery = ({ id, tokenUri, networkId, skip, skipCaching }: NFTQueryProps) => queryOptions({ - queryKey: ['token', 'non-fungible', 'data', id], + queryKey: ['token', 'non-fungible', 'data', getId(id, skipCaching)], // We don't want to delete the NFT data when the user navigates away from NFT components. - ...getQueryConfig({ staleTime: ONE_DAY_MS, gcTime: Infinity, networkId }), + ...getQueryConfig({ staleTime: ONE_DAY_MS, gcTime: Infinity, networkId, skipCaching }), queryFn: !skip && !!tokenUri ? async () => { @@ -203,10 +204,21 @@ export const nftDataQuery = ({ id, tokenUri, networkId, skip }: NFTQueryProps) = : skipToken }) -export const tokenQuery = ({ id, networkId, skip }: TokenQueryProps) => - queryOptions({ - queryKey: ['token', id, { networkId }], - ...getQueryConfig({ staleTime: Infinity, gcTime: Infinity, networkId }), +export const NOCACHE_PREFIX = 'nocache-' + +export const tokenQuery = ({ id: dirtyId, networkId, skip, skipCaching: skipCachingProp }: TokenQueryProps) => { + const isDirtyId = dirtyId.includes(NOCACHE_PREFIX) + const id = isDirtyId ? dirtyId.split(NOCACHE_PREFIX)[1] : dirtyId + const skipCaching = isDirtyId || skipCachingProp + + return queryOptions({ + queryKey: ['token', getId(id, skipCaching), { networkId }], + ...getQueryConfig({ + staleTime: Infinity, + gcTime: Infinity, + networkId, + skipCaching + }), queryFn: async (): Promise => { const nst = { id } as NonStandardToken @@ -218,18 +230,18 @@ export const tokenQuery = ({ id, networkId, skip }: TokenQueryProps) => if (listedFT) return listedFT // 2. If not, find the type of the token - const tokenInfo = await queryClient.fetchQuery(tokenTypeQuery({ id, networkId })) + const tokenInfo = await queryClient.fetchQuery(tokenTypeQuery({ id, networkId, skipCaching })) // 3. If it is a fungible token, fetch the fungible token metadata if (tokenInfo?.stdInterfaceId === e.TokenStdInterfaceId.Fungible) { - const ftMetadata = await queryClient.fetchQuery(fungibleTokenMetadataQuery({ id, networkId })) + const ftMetadata = await queryClient.fetchQuery(fungibleTokenMetadataQuery({ id, networkId, skipCaching })) return ftMetadata ?? nst } // 4. If it is an NFT, fetch the NFT metadata and data if (tokenInfo?.stdInterfaceId === e.TokenStdInterfaceId.NonFungible) { - const nft = await queryClient.fetchQuery(nftQuery({ id, networkId })) + const nft = await queryClient.fetchQuery(nftQuery({ id, networkId, skipCaching })) return nft ?? nst } @@ -246,17 +258,20 @@ export const tokenQuery = ({ id, networkId, skip }: TokenQueryProps) => }, enabled: !skip }) +} -export const nftQuery = ({ id, networkId, skip }: TokenQueryProps) => +export const nftQuery = ({ id, networkId, skip, skipCaching }: TokenQueryProps) => queryOptions({ - queryKey: ['token', 'non-fungible', id, { networkId }], - ...getQueryConfig({ staleTime: Infinity, gcTime: Infinity, networkId }), + queryKey: ['token', 'non-fungible', getId(id, skipCaching), { networkId }], + ...getQueryConfig({ staleTime: Infinity, gcTime: Infinity, networkId, skipCaching }), queryFn: async (): Promise => { - const nftMetadata = await queryClient.fetchQuery(nftMetadataQuery({ id, networkId })) + const nftMetadata = await queryClient.fetchQuery(nftMetadataQuery({ id, networkId, skipCaching })) if (!nftMetadata) return null - const nftData = await queryClient.fetchQuery(nftDataQuery({ id, tokenUri: nftMetadata.tokenUri, networkId })) + const nftData = await queryClient.fetchQuery( + nftDataQuery({ id, tokenUri: nftMetadata.tokenUri, networkId, skipCaching }) + ) if (!nftData) return null @@ -264,3 +279,5 @@ export const nftQuery = ({ id, networkId, skip }: TokenQueryProps) => }, enabled: !skip }) + +const getId = (id: string, skipCaching?: boolean) => `${skipCaching ? NOCACHE_PREFIX : ''}${id}`