diff --git a/apps/minifront/src/components/send/send-form/index.tsx b/apps/minifront/src/components/send/send-form/index.tsx index 38e7690990..f71766f6ab 100644 --- a/apps/minifront/src/components/send/send-form/index.tsx +++ b/apps/minifront/src/components/send/send-form/index.tsx @@ -24,6 +24,7 @@ export const SendForm = () => { memo, fee, feeTier, + assetFeeMetadata, setAmount, setSelection, setRecipient, @@ -97,6 +98,7 @@ export const SendForm = () => { feeTier={feeTier} stakingAssetMetadata={stakingTokenMetadata.data} setFeeTier={setFeeTier} + assetFeeMetadata={assetFeeMetadata} /> [] = [ { @@ -30,23 +30,23 @@ export const GasFee = ({ feeTier, stakingAssetMetadata, setFeeTier, + assetFeeMetadata, }: { fee: Fee | undefined; feeTier: FeeTier_Tier; stakingAssetMetadata?: Metadata; + assetFeeMetadata?: Metadata; setFeeTier: (feeTier: FeeTier_Tier) => void; }) => { - if (!stakingAssetMetadata) { - return null; - } + // If the metadata for the fee asset is undefined, fallback to using the bundled staking asset metadata. + const feeMetadata = assetFeeMetadata ?? stakingAssetMetadata; const feeValueView = new ValueView({ valueView: { case: 'knownAssetId', value: { amount: fee?.amount ?? { hi: 0n, lo: 0n }, - // TODO: once https://github.com/penumbra-zone/web/pull/1468 is merged, change this to metadata: assetFeeMedata - metadata: stakingAssetMetadata, + metadata: feeMetadata, }, }, }); diff --git a/apps/minifront/src/fetchers/registry.ts b/apps/minifront/src/fetchers/registry.ts index 38004b88cf..4b735ecb0b 100644 --- a/apps/minifront/src/fetchers/registry.ts +++ b/apps/minifront/src/fetchers/registry.ts @@ -2,6 +2,7 @@ import { Chain, ChainRegistryClient, Registry } from '@penumbra-labs/registry'; import { useQuery } from '@tanstack/react-query'; import { getChainId } from './chain-id'; import { getAssetMetadataById } from './assets'; +import { AssetId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; export const chainRegistryClient = new ChainRegistryClient(); @@ -34,6 +35,20 @@ export const getStakingTokenMetadata = async () => { return stakingAssetsMetadata; }; +export const getAssetTokenMetadata = async (assetId: AssetId) => { + const chainId = await getChainId(); + if (!chainId) { + throw new Error('Could not fetch chain id'); + } + + const assetTokenMetadata = await getAssetMetadataById(assetId); + + if (!assetTokenMetadata) { + throw new Error('Could not fetch asset token metadata'); + } + return assetTokenMetadata; +}; + export const getChains = async (): Promise => { const chainId = await getChainId(); if (!chainId) { diff --git a/apps/minifront/src/state/send/index.ts b/apps/minifront/src/state/send/index.ts index 0928354103..9fade75cc5 100644 --- a/apps/minifront/src/state/send/index.ts +++ b/apps/minifront/src/state/send/index.ts @@ -5,15 +5,15 @@ import { TransactionPlannerRequest, TransactionPlannerRequest_Output, TransactionPlannerRequest_Spend, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb.js'; +} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; import { BigNumber } from 'bignumber.js'; -import { MemoPlaintext } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb.js'; +import { MemoPlaintext } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb'; import { amountMoreThanBalance, plan, planBuildBroadcast } from '../helpers'; import { Fee, FeeTier_Tier, -} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/fee/v1/fee_pb.js'; +} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/fee/v1/fee_pb'; import { getAssetIdFromValueView, getDisplayDenomExponentFromValueView, @@ -23,6 +23,8 @@ import { toBaseUnit } from '@penumbra-zone/types/lo-hi'; import { isAddress } from '@penumbra-zone/bech32m/penumbra'; import { transferableBalancesResponsesSelector } from './helpers'; import { PartialMessage } from '@bufbuild/protobuf'; +import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; +import { getAssetTokenMetadata } from '../../fetchers/registry'; export interface SendSlice { selection: BalancesResponse | undefined; @@ -41,6 +43,7 @@ export interface SendSlice { txInProgress: boolean; isSendingMax: boolean; setIsSendingMax: (isSendingMax: boolean) => void; + assetFeeMetadata: Metadata | undefined; } export const createSendSlice = (): SliceCreator => (set, get) => { @@ -53,6 +56,7 @@ export const createSendSlice = (): SliceCreator => (set, get) => { feeTier: FeeTier_Tier.LOW, txInProgress: false, isSendingMax: false, + assetFeeMetadata: undefined, setAmount: amount => { set(state => { state.send.amount = amount; @@ -84,18 +88,25 @@ export const createSendSlice = (): SliceCreator => (set, get) => { if (!amount || !recipient || !selection) { set(state => { state.send.fee = undefined; + state.send.assetFeeMetadata = undefined; }); return; } const txPlan = await plan(assembleRequest(get().send)); const fee = txPlan.transactionParameters?.fee; + + // Fetch the asset metadata for the fee if assetId is defined; otherwise, set it to undefined. + // The undefined case occurs when the fee uses the native staking token. + const feeAssetMetadata = fee?.assetId ? await getAssetTokenMetadata(fee.assetId) : undefined; + if (!fee?.amount) { return; } set(state => { state.send.fee = fee; + state.send.assetFeeMetadata = feeAssetMetadata; }); }, setFeeTier: feeTier => {