import React, { useState, useEffect } from 'react'; import { FiHash, FiExternalLink, FiFile, FiLoader } from 'react-icons/fi'; import { Logger } from '@hashgraphonline/standards-sdk'; import { TransactionSection, FieldRow } from './CommonFields'; import { TokenCreationData, TokenMintData, TokenBurnData, TokenUpdateData, TokenDeleteData, TokenAssociateData, TokenDissociateData, TokenFreezeData, TokenUnfreezeData, TokenGrantKycData, TokenRevokeKycData, TokenPauseData, TokenUnpauseData, TokenWipeAccountData, TokenFeeScheduleUpdateData, } from './types'; const logger = new Logger({ module: 'TokenTransactions' }); interface TokenCreationSectionProps { tokenCreationData: TokenCreationData; executedTransactionEntityId?: string | null; type: string; executedTransactionType?: string | null; network?: string; } export const TokenCreationSection: React.FC = ({ tokenCreationData, executedTransactionEntityId, type, executedTransactionType, network = 'testnet', }) => (
{executedTransactionEntityId && (type === 'TOKENCREATE' || type === 'TOKENCREATION' || executedTransactionType === 'TOKENCREATE' || executedTransactionType === 'TOKENCREATION') && (
Created Token ID: {executedTransactionEntityId}
)} {tokenCreationData.memo && (
Token Memo
{tokenCreationData.memo}
)} {tokenCreationData.customFees && tokenCreationData.customFees.length > 0 && (
Custom Fees ({tokenCreationData.customFees.length})
{tokenCreationData.customFees.map((fee, idx) => (
{fee.feeType}: {fee.amount}{' '} {fee.denominatingTokenId ? `(Token: ${fee.denominatingTokenId})` : '(HBAR)'}{' '} → {fee.feeCollectorAccountId}
))}
)}
); interface MetadataViewerProps { hrl: string; network?: string; } const MetadataViewer: React.FC = ({ hrl, network = 'testnet', }) => { const [metadata, setMetadata] = useState<{ name?: string; description?: string; creator?: string; type?: string; image?: string; attributes?: Array<{ trait_type: string; value: string }>; } | null>(null); const [imageUrl, setImageUrl] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { logger.debug('MetadataViewer loading HRL', { hrl }); const fetchMetadata = async () => { try { setLoading(true); setError(null); const match = hrl.match(/hcs:\/\/\d+\/(0\.0\.\d+)/); if (!match || !match[1]) { throw new Error('Invalid HRL format'); } logger.debug('MetadataViewer HRL match found', { match: match[1] }); const topicId = match[1]; logger.debug('MetadataViewer fetching metadata', { topicId, network }); const cdnUrl = `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network || 'testnet'}`; const response = await fetch(cdnUrl); if (!response.ok) { throw new Error('Failed to fetch metadata'); } const data = await response.json(); logger.debug('MetadataViewer metadata loaded', { data }); setMetadata(data); if (data.image) { logger.debug('MetadataViewer processing image', { imageUrl: data.image, }); if (data.image.startsWith('hcs://')) { const imageMatch = data.image.match(/hcs:\/\/\d+\/(0\.0\.\d+)/); if (imageMatch && imageMatch[1]) { setImageUrl( `https://kiloscribe.com/api/inscription-cdn/${imageMatch[1]}?network=${network || 'testnet'}` ); } } else if (data.image.startsWith('https://')) { setImageUrl(data.image); } } } catch (err) { setError( err instanceof Error ? err.message : 'Failed to load metadata' ); } finally { setLoading(false); } }; fetchMetadata(); }, [hrl, network]); if (loading) { return (
Loading metadata...
); } if (error) { return (
Failed to load metadata: {error}
); } if (!metadata) { return null; } return (
{imageUrl && (
{`${metadata.name { e.currentTarget.style.display = 'none'; }} loading='lazy' />
)}
{metadata.name && (
Name: {metadata.name}
)} {metadata.description && (
Description: {metadata.description}
)} {metadata.creator && (
Creator: {metadata.creator}
)} {metadata.type && (
Type: {metadata.type}
)} {metadata.attributes && metadata.attributes.length > 0 && (
Attributes:
{metadata.attributes.map((attr, idx: number) => (
{attr.trait_type}
{attr.value}
))}
)}
); }; export const TokenMintSection: React.FC<{ tokenMint: TokenMintData }> = ({ tokenMint, }) => { const decodeMetadata = (meta: string): string => { try { return atob(meta); } catch { return meta; } }; return (

Token Mint Details

{tokenMint.metadata && tokenMint.metadata.length > 0 && (
Metadata ({tokenMint.metadata.length} items)
{tokenMint.metadata.map((meta, idx) => { const decodedMeta = decodeMetadata(meta); const isHRL = decodedMeta.startsWith('hcs://'); return (
{decodedMeta}
{isHRL && ( )}
); })}
)}
); }; export const TokenBurnSection: React.FC<{ tokenBurn: TokenBurnData }> = ({ tokenBurn, }) => (
{tokenBurn.serialNumbers && tokenBurn.serialNumbers.length > 0 && ( )}
); export const TokenUpdateSection: React.FC<{ tokenUpdate: TokenUpdateData; }> = ({ tokenUpdate }) => (
); export const TokenDeleteSection: React.FC<{ tokenDelete: TokenDeleteData; }> = ({ tokenDelete }) => (
); export const TokenAssociateSection: React.FC<{ tokenAssociate: TokenAssociateData; }> = ({ tokenAssociate }) => (
{tokenAssociate.tokenIds && (
Token IDs ({tokenAssociate.tokenIds.length})
{tokenAssociate.tokenIds.join(', ')}
)}
); export const TokenDissociateSection: React.FC<{ tokenDissociate: TokenDissociateData; }> = ({ tokenDissociate }) => (
{tokenDissociate.tokenIds && (
Token IDs ({tokenDissociate.tokenIds.length})
{tokenDissociate.tokenIds.join(', ')}
)}
); export const TokenFreezeSection: React.FC<{ tokenFreeze: TokenFreezeData; }> = ({ tokenFreeze }) => (
); export const TokenUnfreezeSection: React.FC<{ tokenUnfreeze: TokenUnfreezeData; }> = ({ tokenUnfreeze }) => (
); export const TokenGrantKycSection: React.FC<{ tokenGrantKyc: TokenGrantKycData; }> = ({ tokenGrantKyc }) => (
); export const TokenRevokeKycSection: React.FC<{ tokenRevokeKyc: TokenRevokeKycData; }> = ({ tokenRevokeKyc }) => (
); export const TokenPauseSection: React.FC<{ tokenPause: TokenPauseData }> = ({ tokenPause, }) => (
); export const TokenUnpauseSection: React.FC<{ tokenUnpause: TokenUnpauseData; }> = ({ tokenUnpause }) => (
); export const TokenWipeSection: React.FC<{ tokenWipeAccount: TokenWipeAccountData; }> = ({ tokenWipeAccount }) => (
{tokenWipeAccount.serialNumbers && tokenWipeAccount.serialNumbers.length > 0 && ( )}
); export const TokenFeeScheduleUpdateSection: React.FC<{ tokenFeeScheduleUpdate: TokenFeeScheduleUpdateData; }> = ({ tokenFeeScheduleUpdate }) => (
{tokenFeeScheduleUpdate.customFees && tokenFeeScheduleUpdate.customFees.length > 0 && (
Custom Fees ({tokenFeeScheduleUpdate.customFees.length})
{tokenFeeScheduleUpdate.customFees.map((fee, idx) => (
{fee.feeType}: {fee.amount}{' '} {fee.denominatingTokenId ? `(Token: ${fee.denominatingTokenId})` : '(HBAR)'}{' '} → {fee.feeCollectorAccountId}
))}
)}
);