From cda55a3e54fb615d6d663641de2debfb1754bc86 Mon Sep 17 00:00:00 2001 From: Augusto Lemble Date: Wed, 18 Mar 2026 16:43:42 -0300 Subject: [PATCH 1/7] feat(tooltips): add helper tooltip system with knowledge-level support Add a reusable helper tooltip infrastructure that provides contextual explanations for blockchain data fields across all explorer pages. Infrastructure: - HelperTooltip component: hover/focus/tap with a11y support - FieldLabel wrapper: knowledge-level-aware tooltip visibility - Settings UI: enable/disable toggle + beginner/intermediate/advanced selector - Navbar quick-switcher: cycle through levels with colored border indicator - New `tooltips` i18n namespace with content in all 5 languages Coverage: - EVM transaction page: all fields including L2 (Arbitrum, OP Stack) and blob fields - EVM block page: all fields including More Details (advanced-only) and Arbitrum fields - Address/contract pages: verification, proxy, read/write, balance, nonce, ENS, EIP-7702 - Token/NFT pages: standard, decimals, supply, token ID, owner, approved, metadata URI - Bitcoin transaction/block/address pages: all fields with BTC-specific content - Settings page: knowledge-level selector tooltip --- src/App.tsx | 1 + src/components/common/FieldLabel.tsx | 35 ++++ src/components/common/HelperTooltip.tsx | 168 ++++++++++++++++ src/components/navbar/index.tsx | 85 +++++++- .../pages/bitcoin/BitcoinAddressDisplay.tsx | 27 ++- .../pages/bitcoin/BitcoinBlockDisplay.tsx | 124 ++++++++++-- .../bitcoin/BitcoinTransactionDisplay.tsx | 109 ++++++++-- .../address/shared/AccountMoreInfoCard.tsx | 15 +- .../address/shared/AccountOverviewCard.tsx | 29 ++- .../evm/address/shared/ContractInfoCard.tsx | 22 +- .../address/shared/ContractInteraction.tsx | 10 + .../address/shared/ContractMoreInfoCard.tsx | 15 +- .../evm/address/shared/ERC20TokenInfoCard.tsx | 15 +- .../address/shared/NFTCollectionInfoCard.tsx | 22 +- .../pages/evm/block/BlockDisplay.tsx | 189 +++++++++++++++--- .../evm/tokenDetails/ERC1155TokenDisplay.tsx | 13 +- .../evm/tokenDetails/ERC721TokenDisplay.tsx | 31 ++- .../pages/evm/tx/TransactionDisplay.tsx | 151 +++++++++++--- src/components/pages/evm/tx/TxAnalyser.tsx | 5 + src/components/pages/settings/index.tsx | 72 +++++++ src/i18n.ts | 11 + src/i18next.d.ts | 2 + src/locales/en/common.json | 9 +- src/locales/en/settings.json | 15 ++ src/locales/en/tooltips.json | 128 ++++++++++++ src/locales/es/common.json | 9 +- src/locales/es/settings.json | 15 ++ src/locales/es/tooltips.json | 128 ++++++++++++ src/locales/ja/common.json | 9 +- src/locales/ja/settings.json | 15 ++ src/locales/ja/tooltips.json | 128 ++++++++++++ src/locales/pt-BR/common.json | 9 +- src/locales/pt-BR/settings.json | 15 ++ src/locales/pt-BR/tooltips.json | 128 ++++++++++++ src/locales/zh/common.json | 9 +- src/locales/zh/settings.json | 15 ++ src/locales/zh/tooltips.json | 128 ++++++++++++ src/styles/helper-tooltip.css | 128 ++++++++++++ src/styles/styles.css | 3 +- src/types/index.ts | 9 + 40 files changed, 1925 insertions(+), 126 deletions(-) create mode 100644 src/components/common/FieldLabel.tsx create mode 100644 src/components/common/HelperTooltip.tsx create mode 100644 src/locales/en/tooltips.json create mode 100644 src/locales/es/tooltips.json create mode 100644 src/locales/ja/tooltips.json create mode 100644 src/locales/pt-BR/tooltips.json create mode 100644 src/locales/zh/tooltips.json create mode 100644 src/styles/helper-tooltip.css diff --git a/src/App.tsx b/src/App.tsx index d09f0a50..3a70f196 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -20,6 +20,7 @@ import "./styles/rainbowkit.css"; import "./styles/responsive.css"; import "./styles/ai-analysis.css"; import "./styles/rpcs.css"; +import "./styles/helper-tooltip.css"; import Loading from "./components/common/Loading"; import { diff --git a/src/components/common/FieldLabel.tsx b/src/components/common/FieldLabel.tsx new file mode 100644 index 00000000..1f01b48d --- /dev/null +++ b/src/components/common/FieldLabel.tsx @@ -0,0 +1,35 @@ +import { useTranslation } from "react-i18next"; +import type { KnowledgeLevel } from "../../types"; +import { useSettings } from "../../context/SettingsContext"; +import HelperTooltip from "./HelperTooltip"; + +interface FieldLabelProps { + label: string; + tooltipKey?: string; + visibleFor?: KnowledgeLevel[]; + className?: string; +} + +const FieldLabel: React.FC = ({ + label, + tooltipKey, + visibleFor, + className = "tx-label", +}) => { + const { settings } = useSettings(); + const { t } = useTranslation("tooltips"); + + const level = settings.knowledgeLevel ?? "beginner"; + const tooltipsEnabled = settings.showHelperTooltips !== false; + + const shouldShow = tooltipsEnabled && tooltipKey && (!visibleFor || visibleFor.includes(level)); + + return ( + + {label} + {shouldShow && } + + ); +}; + +export default FieldLabel; diff --git a/src/components/common/HelperTooltip.tsx b/src/components/common/HelperTooltip.tsx new file mode 100644 index 00000000..35a52174 --- /dev/null +++ b/src/components/common/HelperTooltip.tsx @@ -0,0 +1,168 @@ +import { useCallback, useEffect, useId, useRef, useState } from "react"; + +interface HelperTooltipProps { + content: string; + placement?: "top" | "bottom"; + className?: string; +} + +const HOVER_DELAY_MS = 350; + +const HelperTooltip: React.FC = ({ content, placement = "top", className }) => { + const [isVisible, setIsVisible] = useState(false); + const [actualPlacement, setActualPlacement] = useState(placement); + const tooltipId = useId(); + const triggerRef = useRef(null); + const bubbleRef = useRef(null); + const hoverTimeoutRef = useRef | null>(null); + const isPointerInsideRef = useRef(false); + + const show = useCallback(() => { + if (triggerRef.current) { + const rect = triggerRef.current.getBoundingClientRect(); + setActualPlacement(rect.top < 80 ? "bottom" : placement); + } + setIsVisible(true); + }, [placement]); + + const hide = useCallback(() => { + setIsVisible(false); + }, []); + + const clearHoverTimeout = useCallback(() => { + if (hoverTimeoutRef.current) { + clearTimeout(hoverTimeoutRef.current); + hoverTimeoutRef.current = null; + } + }, []); + + const handlePointerEnter = useCallback(() => { + isPointerInsideRef.current = true; + clearHoverTimeout(); + hoverTimeoutRef.current = setTimeout(show, HOVER_DELAY_MS); + }, [show, clearHoverTimeout]); + + const handlePointerLeave = useCallback(() => { + isPointerInsideRef.current = false; + clearHoverTimeout(); + // Small delay to allow moving from trigger to bubble + hoverTimeoutRef.current = setTimeout(() => { + if (!isPointerInsideRef.current) { + hide(); + } + }, 100); + }, [hide, clearHoverTimeout]); + + const handleFocus = useCallback(() => { + show(); + }, [show]); + + const handleBlur = useCallback(() => { + hide(); + }, [hide]); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === "Escape") { + hide(); + } + }, + [hide], + ); + + // Touch: tap to toggle + const handleClick = useCallback(() => { + if (isVisible) { + hide(); + } else { + show(); + } + }, [isVisible, show, hide]); + + // Close on outside click (touch devices) + useEffect(() => { + if (!isVisible) return; + + const handleOutsideClick = (e: MouseEvent | TouchEvent) => { + const target = e.target as Node; + if ( + triggerRef.current && + !triggerRef.current.contains(target) && + bubbleRef.current && + !bubbleRef.current.contains(target) + ) { + hide(); + } + }; + + document.addEventListener("mousedown", handleOutsideClick); + document.addEventListener("touchstart", handleOutsideClick); + return () => { + document.removeEventListener("mousedown", handleOutsideClick); + document.removeEventListener("touchstart", handleOutsideClick); + }; + }, [isVisible, hide]); + + // Cleanup timeout on unmount + useEffect(() => { + return () => { + if (hoverTimeoutRef.current) { + clearTimeout(hoverTimeoutRef.current); + } + }; + }, []); + + return ( + + + {isVisible && ( + + )} + + ); +}; + +export default HelperTooltip; diff --git a/src/components/navbar/index.tsx b/src/components/navbar/index.tsx index aa6b0240..61c3d709 100644 --- a/src/components/navbar/index.tsx +++ b/src/components/navbar/index.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useLocation, useNavigate } from "react-router-dom"; import { useSettings } from "../../context/SettingsContext"; +import { useNotify } from "../../hooks/useNotify"; import { useSearch } from "../../hooks/useSearch"; import NavbarLogo from "./NavbarLogo"; import { NetworkBlockIndicator } from "./NetworkBlockIndicator"; @@ -13,7 +14,9 @@ const Navbar = () => { const location = useLocation(); const { searchTerm, setSearchTerm, isResolving, error, clearError, handleSearch, networkId } = useSearch(); - const { isDarkMode, toggleTheme, isSuperUser, toggleSuperUserMode } = useSettings(); + const { isDarkMode, toggleTheme, isSuperUser, toggleSuperUserMode, settings, updateSettings } = + useSettings(); + const notify = useNotify(); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); // Check if we should show the search box (on any network page including home) @@ -42,6 +45,30 @@ const Navbar = () => { }; }, [isMobileMenuOpen]); + const knowledgeLevel = settings.knowledgeLevel ?? "beginner"; + const tooltipsEnabled = settings.showHelperTooltips !== false; + + const cycleKnowledgeLevel = () => { + const levels = ["beginner", "intermediate", "advanced"] as const; + const currentIndex = levels.indexOf(knowledgeLevel); + const nextLevel = levels[(currentIndex + 1) % levels.length] ?? "beginner"; + updateSettings({ knowledgeLevel: nextLevel }); + const levelKey = + nextLevel === "beginner" + ? "nav.tooltipsLevelBeginner" + : nextLevel === "intermediate" + ? "nav.tooltipsLevelIntermediate" + : "nav.tooltipsLevelAdvanced"; + notify.success(t("nav.tooltipsSwitched", { level: t(levelKey) }), 2000); + }; + + const knowledgeLevelLabel = + knowledgeLevel === "beginner" + ? t("nav.tooltipsBeginner") + : knowledgeLevel === "intermediate" + ? t("nav.tooltipsIntermediate") + : t("nav.tooltipsAdvanced"); + const goToSettings = () => { navigate("/settings"); }; @@ -137,6 +164,40 @@ const Navbar = () => { )} + {tooltipsEnabled && ( +
  • + +
  • + )}
  • + {/* Tooltip Level toggle */} + {tooltipsEnabled && ( + + )} + {/* Super User Mode toggle */} )} {isSuperUser && ( diff --git a/src/components/pages/settings/index.tsx b/src/components/pages/settings/index.tsx index 5bf1f322..9b2bc7ed 100644 --- a/src/components/pages/settings/index.tsx +++ b/src/components/pages/settings/index.tsx @@ -2,6 +2,7 @@ import type React from "react"; import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; +import HelperTooltip from "../../common/HelperTooltip"; import { MetaMaskIcon } from "../../common/MetaMaskIcon"; import { getEnabledNetworks } from "../../../config/networks"; import { AppContext, useNetworks } from "../../../context/AppContext"; @@ -87,6 +88,7 @@ const isAlchemyUrl = (url: string): boolean => url.includes("alchemy.com"); const Settings: React.FC = () => { const { t, i18n } = useTranslation("settings"); + const { t: tTooltips } = useTranslation("tooltips"); const location = useLocation(); const navigate = useNavigate(); const { rpcUrls, setRpcUrls } = useContext(AppContext); @@ -913,6 +915,76 @@ const Settings: React.FC = () => { + +
    +

    💡 {t("helperTooltips.title")}

    +

    + {t("helperTooltips.description")} +

    + +
    +
    +
    + {t("helperTooltips.enabled.label")} +
    +
    + {t("helperTooltips.enabled.description")} +
    +
    + +
    + +
    +
    +
    + {t("helperTooltips.knowledgeLevel.label")} + {settings.showHelperTooltips !== false && ( + + )} +
    +
    + {t("helperTooltips.knowledgeLevel.description")} +
    +
    + +
    +
    )} diff --git a/src/i18n.ts b/src/i18n.ts index f31fe572..021b03b8 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -12,6 +12,7 @@ import enSettings from "./locales/en/settings.json"; import enTransaction from "./locales/en/transaction.json"; import enTokenDetails from "./locales/en/tokenDetails.json"; import enRpcs from "./locales/en/rpcs.json"; +import enTooltips from "./locales/en/tooltips.json"; import esAddress from "./locales/es/address.json"; import esBlock from "./locales/es/block.json"; @@ -23,6 +24,7 @@ import esSettings from "./locales/es/settings.json"; import esTransaction from "./locales/es/transaction.json"; import esTokenDetails from "./locales/es/tokenDetails.json"; import esRpcs from "./locales/es/rpcs.json"; +import esTooltips from "./locales/es/tooltips.json"; import zhAddress from "./locales/zh/address.json"; import zhBlock from "./locales/zh/block.json"; @@ -33,6 +35,7 @@ import zhNetwork from "./locales/zh/network.json"; import zhSettings from "./locales/zh/settings.json"; import zhTransaction from "./locales/zh/transaction.json"; import zhTokenDetails from "./locales/zh/tokenDetails.json"; +import zhTooltips from "./locales/zh/tooltips.json"; import jaAddress from "./locales/ja/address.json"; import jaBlock from "./locales/ja/block.json"; @@ -43,6 +46,7 @@ import jaNetwork from "./locales/ja/network.json"; import jaSettings from "./locales/ja/settings.json"; import jaTransaction from "./locales/ja/transaction.json"; import jaTokenDetails from "./locales/ja/tokenDetails.json"; +import jaTooltips from "./locales/ja/tooltips.json"; import ptBRAddress from "./locales/pt-BR/address.json"; import ptBRBlock from "./locales/pt-BR/block.json"; @@ -53,6 +57,7 @@ import ptBRNetwork from "./locales/pt-BR/network.json"; import ptBRSettings from "./locales/pt-BR/settings.json"; import ptBRTransaction from "./locales/pt-BR/transaction.json"; import ptBRTokenDetails from "./locales/pt-BR/tokenDetails.json"; +import ptBRTooltips from "./locales/pt-BR/tooltips.json"; export const SUPPORTED_LANGUAGES = [ { code: "en", name: "English" }, @@ -78,6 +83,7 @@ i18n network: enNetwork, tokenDetails: enTokenDetails, rpcs: enRpcs, + tooltips: enTooltips, }, es: { common: esCommon, @@ -90,6 +96,7 @@ i18n network: esNetwork, tokenDetails: esTokenDetails, rpcs: esRpcs, + tooltips: esTooltips, }, zh: { common: zhCommon, @@ -101,6 +108,7 @@ i18n devtools: zhDevtools, network: zhNetwork, tokenDetails: zhTokenDetails, + tooltips: zhTooltips, }, ja: { common: jaCommon, @@ -112,6 +120,7 @@ i18n devtools: jaDevtools, network: jaNetwork, tokenDetails: jaTokenDetails, + tooltips: jaTooltips, }, "pt-BR": { common: ptBRCommon, @@ -123,6 +132,7 @@ i18n devtools: ptBRDevtools, network: ptBRNetwork, tokenDetails: ptBRTokenDetails, + tooltips: ptBRTooltips, }, }, fallbackLng: "en", @@ -137,6 +147,7 @@ i18n "devtools", "network", "rpcs", + "tooltips", ], interpolation: { escapeValue: false, diff --git a/src/i18next.d.ts b/src/i18next.d.ts index 19b600e2..d1122d44 100644 --- a/src/i18next.d.ts +++ b/src/i18next.d.ts @@ -8,6 +8,7 @@ import type settings from "./locales/en/settings.json"; import type transaction from "./locales/en/transaction.json"; import type tokenDetails from "./locales/en/tokenDetails.json"; import type rpcs from "./locales/en/rpcs.json"; +import type tooltips from "./locales/en/tooltips.json"; declare module "i18next" { interface CustomTypeOptions { defaultNS: "common"; @@ -22,6 +23,7 @@ declare module "i18next" { network: typeof network; tokenDetails: typeof tokenDetails; rpcs: typeof rpcs; + tooltips: typeof tooltips; }; } } diff --git a/src/locales/en/common.json b/src/locales/en/common.json index 1313d994..b3b3757c 100644 --- a/src/locales/en/common.json +++ b/src/locales/en/common.json @@ -27,7 +27,14 @@ "enableSuperUser": "Enable Super User Mode", "mempool": "Mempool", "txs": "Transactions", - "superUserBadge": "Super User" + "superUserBadge": "Super User", + "tooltipsBeginner": "Tooltips: Beginner", + "tooltipsIntermediate": "Tooltips: Intermediate", + "tooltipsAdvanced": "Tooltips: Advanced", + "tooltipsSwitched": "Tooltip helper level switched to {{level}}", + "tooltipsLevelBeginner": "Beginner", + "tooltipsLevelIntermediate": "Intermediate", + "tooltipsLevelAdvanced": "Advanced" }, "footer": { "about": "About", diff --git a/src/locales/en/settings.json b/src/locales/en/settings.json index 7f9b9898..02e02876 100644 --- a/src/locales/en/settings.json +++ b/src/locales/en/settings.json @@ -149,6 +149,21 @@ } } }, + "helperTooltips": { + "title": "Helper Tooltips", + "description": "Show contextual help for blockchain data fields.", + "enabled": { + "label": "Show Helper Tooltips", + "description": "Display helper icons next to field labels with brief explanations." + }, + "knowledgeLevel": { + "label": "Knowledge Level", + "description": "Controls how many helper tooltips are shown. Beginner shows the most, Advanced shows the fewest.", + "beginner": "Beginner", + "intermediate": "Intermediate", + "advanced": "Advanced" + } + }, "rpcEndpoints": { "title": "RPC Endpoints", "description": "Configure RPC URLs for each network. Click on a network to expand and configure its endpoints.", diff --git a/src/locales/en/tooltips.json b/src/locales/en/tooltips.json new file mode 100644 index 00000000..e99ee5e7 --- /dev/null +++ b/src/locales/en/tooltips.json @@ -0,0 +1,128 @@ +{ + "transaction": { + "hash": "A unique identifier for this transaction, generated from its contents.", + "from": "The address that initiated and signed this transaction.", + "status": "Whether the transaction executed successfully or reverted.", + "confirmations": "Blocks mined after this transaction. More confirmations means higher finality.", + "interactedWith": "The contract this transaction called, or the recipient address for simple transfers.", + "transactionFee": "Total fee paid to process this transaction (gas used × gas price).", + "gasPrice": "Price per unit of gas, in Gwei. Higher gas prices incentivize faster inclusion.", + "gasLimitUsage": "Gas limit is the maximum gas authorized. Gas used is the actual amount consumed.", + "nonce": "Sender's transaction counter. Ensures transactions are processed in order.", + "position": "The index of this transaction within its block. Lower positions were processed first.", + "type": "The transaction format (e.g. Legacy, EIP-1559, EIP-4844). Determines which fee fields apply.", + "decodedInput": "The function call and parameters sent to the contract, decoded into human-readable form.", + "maxFeePerBlobGas": "Maximum price per unit of blob gas the sender is willing to pay for data availability.", + "blobGasPrice": "Actual price per unit of blob gas paid in this block.", + "blobGasUsed": "Amount of blob gas consumed by this transaction's data blobs.", + "blobCount": "Number of data blobs attached to this transaction for rollup data availability.", + "blobVersionedHashes": "Versioned hashes that uniquely identify each data blob committed by this transaction.", + "contractCreated": "The address of the new contract deployed by this transaction.", + "value": "Amount of native currency (e.g. ETH) transferred in this transaction.", + "effectiveGasPrice": "The actual gas price paid after EIP-1559 fee calculation, which may differ from the requested price.", + "l1BlockNumber": "The Ethereum L1 block that anchors this L2 transaction for security.", + "gasUsedForL1": "Gas consumed for posting this transaction's data to Ethereum L1.", + "l1Fee": "Fee paid for data availability on Ethereum L1. Part of the total transaction cost on this L2.", + "l1GasPrice": "The L1 gas price used to calculate the data availability fee component.", + "l1GasUsed": "Estimated L1 gas required to post this transaction's calldata.", + "l1FeeScalar": "A multiplier applied to the L1 fee calculation by the L2 sequencer." + }, + "block": { + "hash": "A unique fingerprint identifying this block, derived from its contents.", + "transactions": "The number of transactions included and executed in this block.", + "withdrawals": "Validator withdrawals processed in this block, returning staked ETH.", + "feeRecipient": "The address that receives priority fees from transactions in this block.", + "difficulty": "Mining difficulty for this block. Always zero on proof-of-stake networks after the Merge.", + "totalDifficulty": "Cumulative difficulty of the chain up to this block. Legacy field from proof-of-work.", + "size": "The total size of the block data in bytes.", + "extraData": "Arbitrary data set by the block producer. Often contains client or pool identifiers.", + "gasUsed": "Total gas consumed by all transactions in this block.", + "gasLimit": "Maximum gas allowed in this block, defining its capacity.", + "baseFeePerGas": "Minimum gas price for this block, set by the network based on demand (EIP-1559).", + "burntFees": "Transaction fees permanently removed from circulation via EIP-1559.", + "blobGasUsed": "Total blob gas consumed by blob transactions in this block.", + "excessBlobGas": "Blob gas above the target, used to calculate the next block's blob base fee.", + "blobCount": "Number of data blobs included in this block for rollup data availability.", + "l1BlockNumber": "The Ethereum L1 block number associated with this Arbitrum block.", + "sendCount": "Number of outgoing L2-to-L1 messages sent in this Arbitrum block.", + "sendRoot": "Merkle root of all outgoing L2-to-L1 messages, used for cross-layer verification.", + "parentHash": "Hash of the previous block in the chain, linking blocks together.", + "stateRoot": "Merkle root of the entire blockchain state after processing this block.", + "transactionsRoot": "Merkle root of all transactions included in this block.", + "receiptsRoot": "Merkle root of all transaction receipts from this block.", + "withdrawalsRoot": "Merkle root of all validator withdrawals processed in this block.", + "logsBloom": "A bloom filter for efficiently searching event logs emitted in this block.", + "nonce": "A value used in proof-of-work mining. Always zero after the Merge.", + "mixHash": "A hash used in the proof-of-work algorithm. Replaced by RANDAO value after the Merge.", + "sha3Uncles": "Hash of the uncle blocks list. Always the empty list hash after the Merge.", + "validator": "The validator index that initiated this withdrawal from the beacon chain." + }, + "address": { + "verification": "A verified contract has its source code publicly confirmed to match the deployed bytecode.", + "proxyType": "This contract uses an upgradeable proxy pattern. The logic lives in a separate implementation contract.", + "readContract": "Query contract data without spending gas or connecting a wallet. Read-only calls.", + "writeContract": "Send a transaction that changes contract state. Requires a connected wallet and gas.", + "balance": "Native currency balance held by this address.", + "usdValue": "Estimated fiat value based on current market price.", + "nonce": "Number of transactions sent from this address. Used for transaction ordering.", + "eip7702Delegate": "This account delegates its code execution to another address via EIP-7702.", + "implementationAddress": "The contract that contains the actual logic for this proxy.", + "ensName": "Ethereum Name Service name associated with this address.", + "ensApp": "Application or resolver linked to this ENS name." + }, + "token": { + "tokenStandard": "The token interface standard (e.g. ERC-20, ERC-721, ERC-1155) that defines how this token behaves.", + "decimals": "Number of decimal places used to display token amounts. Most ERC-20 tokens use 18.", + "totalSupply": "Total number of tokens that have been created for this contract.", + "tokenId": "A unique numeric identifier for this specific token within its collection.", + "owner": "The address that currently holds this NFT.", + "approved": "An address authorized to transfer this specific NFT on behalf of the owner.", + "metadataUri": "The URI where this token's metadata (name, image, attributes) is stored." + }, + "bitcoin": { + "txid": "A unique identifier for this transaction, computed from its serialized data.", + "witnessHash": "Transaction hash including witness (SegWit) data. Differs from TXID for SegWit transactions.", + "block": "The block that includes this transaction.", + "status": "Whether this transaction has been confirmed in a block or is still waiting in the mempool.", + "inputs": "The number of previous outputs being spent. Each input references a UTXO.", + "outputs": "The number of new outputs created. Each output locks BTC to an address.", + "fee": "The difference between total inputs and total outputs, paid to the miner.", + "feePerByte": "Fee rate in satoshis per byte of raw transaction data.", + "feePerVByte": "Fee rate in satoshis per virtual byte. The standard fee metric for SegWit transactions.", + "feePerWU": "Fee rate in satoshis per weight unit. The most granular fee metric.", + "size": "Raw transaction size in bytes, including witness data.", + "virtualSize": "Adjusted transaction size that discounts witness data. Used for fee calculation.", + "weight": "Transaction weight in weight units (WU). 1 vByte = 4 WU.", + "coinbase": "Whether this is a coinbase transaction that creates new BTC as a block reward.", + "witness": "Whether this transaction uses Segregated Witness (SegWit) format.", + "rbf": "Replace-By-Fee. If enabled, this transaction can be replaced by one with a higher fee before confirmation.", + "version": "Transaction format version number. Determines which features are available.", + "locktime": "Earliest block height or time when this transaction can be included in a block.", + "blockHash": "The unique hash identifying the block that contains this transaction.", + "minedBy": "The mining pool or entity that produced this block.", + "blockReward": "New BTC created as a reward for mining this block (subsidy + fees).", + "totalFees": "Sum of all transaction fees collected by the miner in this block.", + "feeRate": "Average and median fee rates of transactions in this block.", + "transactions": "Number of transactions included in this block.", + "totalOutput": "Total BTC value of all outputs created in this block.", + "difficulty": "How hard it is to find a valid block hash. Adjusts every 2016 blocks.", + "blockSize": "Total size of the serialized block data.", + "blockWeight": "Block weight in weight units. Maximum is 4,000,000 WU.", + "previousBlock": "Hash of the preceding block, linking this block to the chain.", + "nextBlock": "Hash of the following block, if one exists.", + "coinbaseMessage": "Arbitrary text embedded in the coinbase transaction by the miner.", + "merkleRoot": "Root hash of the Merkle tree of all transactions in this block.", + "blockVersion": "Block format version. Encodes which consensus rules and soft forks are signaled.", + "bits": "Compact encoding of the target threshold for a valid block hash.", + "blockNonce": "A value miners iterate to find a block hash below the target.", + "coinbaseHex": "Raw hexadecimal data of the coinbase transaction input.", + "address": "A Bitcoin address derived from a public key, used to receive BTC.", + "balance": "Total BTC held by this address across all unspent outputs.", + "totalReceived": "Cumulative BTC received by this address across all transactions.", + "utxos": "Unspent Transaction Outputs. Individual coins available to be spent by this address.", + "txCount": "Total number of transactions involving this address." + }, + "settings": { + "knowledgeLevel": "Controls how much explanatory help is shown throughout the explorer." + } +} diff --git a/src/locales/es/common.json b/src/locales/es/common.json index c37a511a..87fadd57 100644 --- a/src/locales/es/common.json +++ b/src/locales/es/common.json @@ -27,7 +27,14 @@ "enableSuperUser": "Activar modo Super Usuario", "mempool": "Mempool", "txs": "Transacciones", - "superUserBadge": "Super Usuario" + "superUserBadge": "Super Usuario", + "tooltipsBeginner": "Tooltips: Principiante", + "tooltipsIntermediate": "Tooltips: Intermedio", + "tooltipsAdvanced": "Tooltips: Avanzado", + "tooltipsSwitched": "Nivel de tooltips cambiado a {{level}}", + "tooltipsLevelBeginner": "Principiante", + "tooltipsLevelIntermediate": "Intermedio", + "tooltipsLevelAdvanced": "Avanzado" }, "footer": { "about": "Acerca de", diff --git a/src/locales/es/settings.json b/src/locales/es/settings.json index 620b9f04..b4cf270a 100644 --- a/src/locales/es/settings.json +++ b/src/locales/es/settings.json @@ -149,6 +149,21 @@ } } }, + "helperTooltips": { + "title": "Tooltips de Ayuda", + "description": "Mostrar ayuda contextual para campos de datos de blockchain.", + "enabled": { + "label": "Mostrar Tooltips de Ayuda", + "description": "Mostrar íconos de ayuda junto a las etiquetas de campos con explicaciones breves." + }, + "knowledgeLevel": { + "label": "Nivel de Conocimiento", + "description": "Controla cuántos tooltips de ayuda se muestran. Principiante muestra más, Avanzado muestra menos.", + "beginner": "Principiante", + "intermediate": "Intermedio", + "advanced": "Avanzado" + } + }, "rpcEndpoints": { "title": "Endpoints RPC", "description": "Configurá las URLs RPC para cada red. Hacé click en una red para desplegar y configurar sus endpoints.", diff --git a/src/locales/es/tooltips.json b/src/locales/es/tooltips.json new file mode 100644 index 00000000..079e9877 --- /dev/null +++ b/src/locales/es/tooltips.json @@ -0,0 +1,128 @@ +{ + "transaction": { + "hash": "Un identificador único para esta transacción, generado a partir de su contenido.", + "from": "La dirección que inició y firmó esta transacción.", + "status": "Si la transacción se ejecutó correctamente o fue revertida.", + "confirmations": "Bloques minados después de esta transacción. Más confirmaciones significa mayor finalidad.", + "interactedWith": "El contrato con el que interactuó esta transacción, o la dirección del destinatario en transferencias simples.", + "transactionFee": "Tarifa total pagada para procesar esta transacción (gas usado × precio del gas).", + "gasPrice": "Precio por unidad de gas, en Gwei. Precios más altos incentivan una inclusión más rápida.", + "gasLimitUsage": "El límite de gas es el máximo autorizado. El gas usado es la cantidad real consumida.", + "nonce": "Contador de transacciones del remitente. Asegura que las transacciones se procesen en orden.", + "position": "El índice de esta transacción dentro de su bloque. Posiciones más bajas se procesaron primero.", + "type": "El formato de la transacción (ej. Legacy, EIP-1559, EIP-4844). Determina qué campos de tarifa aplican.", + "decodedInput": "La llamada a función y parámetros enviados al contrato, decodificados en formato legible.", + "maxFeePerBlobGas": "Precio máximo por unidad de blob gas que el remitente está dispuesto a pagar por disponibilidad de datos.", + "blobGasPrice": "Precio real por unidad de blob gas pagado en este bloque.", + "blobGasUsed": "Cantidad de blob gas consumido por los blobs de datos de esta transacción.", + "blobCount": "Cantidad de blobs de datos adjuntos a esta transacción para disponibilidad de datos de rollup.", + "blobVersionedHashes": "Hashes versionados que identifican de forma única cada blob de datos comprometido por esta transacción.", + "contractCreated": "La dirección del nuevo contrato desplegado por esta transacción.", + "value": "Cantidad de moneda nativa (ej. ETH) transferida en esta transacción.", + "effectiveGasPrice": "El precio de gas real pagado después del cálculo de tarifa EIP-1559, que puede diferir del precio solicitado.", + "l1BlockNumber": "El bloque de Ethereum L1 que ancla esta transacción L2 para seguridad.", + "gasUsedForL1": "Gas consumido para publicar los datos de esta transacción en Ethereum L1.", + "l1Fee": "Tarifa pagada por disponibilidad de datos en Ethereum L1. Parte del costo total de la transacción en esta L2.", + "l1GasPrice": "El precio de gas L1 usado para calcular el componente de tarifa de disponibilidad de datos.", + "l1GasUsed": "Gas L1 estimado requerido para publicar los calldata de esta transacción.", + "l1FeeScalar": "Un multiplicador aplicado al cálculo de tarifa L1 por el secuenciador L2." + }, + "block": { + "hash": "Una huella digital única que identifica este bloque, derivada de su contenido.", + "transactions": "La cantidad de transacciones incluidas y ejecutadas en este bloque.", + "withdrawals": "Retiros de validadores procesados en este bloque, devolviendo ETH stakeado.", + "feeRecipient": "La dirección que recibe las tarifas prioritarias de las transacciones en este bloque.", + "difficulty": "Dificultad de minado para este bloque. Siempre cero en redes proof-of-stake después del Merge.", + "totalDifficulty": "Dificultad acumulada de la cadena hasta este bloque. Campo heredado de proof-of-work.", + "size": "El tamaño total de los datos del bloque en bytes.", + "extraData": "Datos arbitrarios establecidos por el productor del bloque. A menudo contiene identificadores de cliente o pool.", + "gasUsed": "Gas total consumido por todas las transacciones en este bloque.", + "gasLimit": "Gas máximo permitido en este bloque, definiendo su capacidad.", + "baseFeePerGas": "Precio mínimo de gas para este bloque, establecido por la red según la demanda (EIP-1559).", + "burntFees": "Tarifas de transacción eliminadas permanentemente de la circulación mediante EIP-1559.", + "blobGasUsed": "Blob gas total consumido por transacciones blob en este bloque.", + "excessBlobGas": "Blob gas por encima del objetivo, usado para calcular la tarifa base blob del siguiente bloque.", + "blobCount": "Cantidad de blobs de datos incluidos en este bloque para disponibilidad de datos de rollup.", + "l1BlockNumber": "El número de bloque de Ethereum L1 asociado con este bloque de Arbitrum.", + "sendCount": "Cantidad de mensajes salientes L2-a-L1 enviados en este bloque de Arbitrum.", + "sendRoot": "Raíz de Merkle de todos los mensajes salientes L2-a-L1, usada para verificación entre capas.", + "parentHash": "Hash del bloque anterior en la cadena, enlazando los bloques entre sí.", + "stateRoot": "Raíz de Merkle del estado completo de la blockchain después de procesar este bloque.", + "transactionsRoot": "Raíz de Merkle de todas las transacciones incluidas en este bloque.", + "receiptsRoot": "Raíz de Merkle de todos los recibos de transacciones de este bloque.", + "withdrawalsRoot": "Raíz de Merkle de todos los retiros de validadores procesados en este bloque.", + "logsBloom": "Un filtro bloom para buscar eficientemente logs de eventos emitidos en este bloque.", + "nonce": "Un valor usado en minería proof-of-work. Siempre cero después del Merge.", + "mixHash": "Un hash usado en el algoritmo proof-of-work. Reemplazado por el valor RANDAO después del Merge.", + "sha3Uncles": "Hash de la lista de bloques uncle. Siempre el hash de lista vacía después del Merge.", + "validator": "El índice del validador que inició este retiro desde la beacon chain." + }, + "address": { + "verification": "Un contrato verificado tiene su código fuente confirmado públicamente como coincidente con el bytecode desplegado.", + "proxyType": "Este contrato usa un patrón de proxy actualizable. La lógica está en un contrato de implementación separado.", + "readContract": "Consultar datos del contrato sin gastar gas ni conectar una wallet. Llamadas de solo lectura.", + "writeContract": "Enviar una transacción que cambia el estado del contrato. Requiere una wallet conectada y gas.", + "balance": "Saldo de moneda nativa que posee esta dirección.", + "usdValue": "Valor estimado en moneda fiat basado en el precio de mercado actual.", + "nonce": "Cantidad de transacciones enviadas desde esta dirección. Usado para ordenar transacciones.", + "eip7702Delegate": "Esta cuenta delega la ejecución de su código a otra dirección vía EIP-7702.", + "implementationAddress": "El contrato que contiene la lógica real para este proxy.", + "ensName": "Nombre del Ethereum Name Service asociado a esta dirección.", + "ensApp": "Aplicación o resolver vinculado a este nombre ENS." + }, + "token": { + "tokenStandard": "El estándar de interfaz del token (ej. ERC-20, ERC-721, ERC-1155) que define cómo se comporta.", + "decimals": "Cantidad de decimales usados para mostrar montos del token. La mayoría de tokens ERC-20 usan 18.", + "totalSupply": "Cantidad total de tokens creados para este contrato.", + "tokenId": "Un identificador numérico único para este token específico dentro de su colección.", + "owner": "La dirección que actualmente posee este NFT.", + "approved": "Una dirección autorizada para transferir este NFT específico en nombre del propietario.", + "metadataUri": "La URI donde se almacenan los metadatos de este token (nombre, imagen, atributos)." + }, + "bitcoin": { + "txid": "Un identificador único para esta transacción, calculado a partir de sus datos serializados.", + "witnessHash": "Hash de transacción incluyendo datos witness (SegWit). Difiere del TXID para transacciones SegWit.", + "block": "El bloque que incluye esta transacción.", + "status": "Si esta transacción fue confirmada en un bloque o sigue esperando en el mempool.", + "inputs": "La cantidad de salidas previas que se gastan. Cada entrada referencia un UTXO.", + "outputs": "La cantidad de nuevas salidas creadas. Cada salida bloquea BTC a una dirección.", + "fee": "La diferencia entre entradas y salidas totales, pagada al minero.", + "feePerByte": "Tasa de tarifa en satoshis por byte de datos crudos de transacción.", + "feePerVByte": "Tasa de tarifa en satoshis por byte virtual. La métrica estándar para transacciones SegWit.", + "feePerWU": "Tasa de tarifa en satoshis por unidad de peso. La métrica de tarifa más granular.", + "size": "Tamaño crudo de la transacción en bytes, incluyendo datos witness.", + "virtualSize": "Tamaño ajustado que descuenta datos witness. Usado para calcular tarifas.", + "weight": "Peso de la transacción en unidades de peso (WU). 1 vByte = 4 WU.", + "coinbase": "Si esta es una transacción coinbase que crea nuevos BTC como recompensa de bloque.", + "witness": "Si esta transacción usa el formato Segregated Witness (SegWit).", + "rbf": "Replace-By-Fee. Si está habilitado, esta transacción puede ser reemplazada por una con mayor tarifa antes de la confirmación.", + "version": "Número de versión del formato de transacción. Determina qué funciones están disponibles.", + "locktime": "La altura de bloque o momento más temprano en que esta transacción puede incluirse en un bloque.", + "blockHash": "El hash único que identifica el bloque que contiene esta transacción.", + "minedBy": "El pool de minería o entidad que produjo este bloque.", + "blockReward": "Nuevos BTC creados como recompensa por minar este bloque (subsidio + tarifas).", + "totalFees": "Suma de todas las tarifas de transacción cobradas por el minero en este bloque.", + "feeRate": "Tasas de tarifa promedio y mediana de las transacciones en este bloque.", + "transactions": "Cantidad de transacciones incluidas en este bloque.", + "totalOutput": "Valor total de BTC de todas las salidas creadas en este bloque.", + "difficulty": "Qué tan difícil es encontrar un hash de bloque válido. Se ajusta cada 2016 bloques.", + "blockSize": "Tamaño total de los datos serializados del bloque.", + "blockWeight": "Peso del bloque en unidades de peso. Máximo: 4.000.000 WU.", + "previousBlock": "Hash del bloque precedente, enlazando este bloque a la cadena.", + "nextBlock": "Hash del bloque siguiente, si existe.", + "coinbaseMessage": "Texto arbitrario incrustado en la transacción coinbase por el minero.", + "merkleRoot": "Hash raíz del árbol de Merkle de todas las transacciones en este bloque.", + "blockVersion": "Versión del formato de bloque. Codifica qué reglas de consenso y soft forks se señalizan.", + "bits": "Codificación compacta del umbral objetivo para un hash de bloque válido.", + "blockNonce": "Un valor que los mineros iteran para encontrar un hash de bloque por debajo del objetivo.", + "coinbaseHex": "Datos hexadecimales crudos de la entrada de la transacción coinbase.", + "address": "Una dirección Bitcoin derivada de una clave pública, usada para recibir BTC.", + "balance": "BTC total que posee esta dirección en todas las salidas sin gastar.", + "totalReceived": "BTC acumulados recibidos por esta dirección en todas las transacciones.", + "utxos": "Salidas de Transacción No Gastadas. Monedas individuales disponibles para gastar por esta dirección.", + "txCount": "Cantidad total de transacciones que involucran esta dirección." + }, + "settings": { + "knowledgeLevel": "Controla cuánta ayuda explicativa se muestra en el explorador." + } +} diff --git a/src/locales/ja/common.json b/src/locales/ja/common.json index d444404e..b11fc25c 100644 --- a/src/locales/ja/common.json +++ b/src/locales/ja/common.json @@ -26,7 +26,14 @@ "disableSuperUser": "スーパーユーザーモードを無効化", "enableSuperUser": "スーパーユーザーモードを有効化", "mempool": "メモリープール", - "txs": "トランザクション" + "txs": "トランザクション", + "tooltipsBeginner": "ツールチップ:初心者", + "tooltipsIntermediate": "ツールチップ:中級者", + "tooltipsAdvanced": "ツールチップ:上級者", + "tooltipsSwitched": "ツールチップヘルパーレベルが{{level}}に切り替わりました", + "tooltipsLevelBeginner": "初心者", + "tooltipsLevelIntermediate": "中級者", + "tooltipsLevelAdvanced": "上級者" }, "footer": { "about": "概要", diff --git a/src/locales/ja/settings.json b/src/locales/ja/settings.json index 3ded7c54..a50abd00 100644 --- a/src/locales/ja/settings.json +++ b/src/locales/ja/settings.json @@ -149,6 +149,21 @@ } } }, + "helperTooltips": { + "title": "ヘルパーツールチップ", + "description": "ブロックチェーンデータフィールドのコンテキストヘルプを表示します。", + "enabled": { + "label": "ヘルパーツールチップを表示", + "description": "フィールドラベルの横に簡単な説明付きのヘルプアイコンを表示します。" + }, + "knowledgeLevel": { + "label": "知識レベル", + "description": "ヘルパーツールチップの表示数を制御します。初心者は最も多く、上級者は最も少なく表示されます。", + "beginner": "初心者", + "intermediate": "中級者", + "advanced": "上級者" + } + }, "rpcEndpoints": { "title": "RPCエンドポイント", "description": "各ネットワークのRPC URLを設定します。ネットワークをクリックして展開し、エンドポイントを設定してください。", diff --git a/src/locales/ja/tooltips.json b/src/locales/ja/tooltips.json new file mode 100644 index 00000000..65264a25 --- /dev/null +++ b/src/locales/ja/tooltips.json @@ -0,0 +1,128 @@ +{ + "transaction": { + "hash": "このトランザクションの一意の識別子。内容から生成されます。", + "from": "このトランザクションを開始し署名したアドレス。", + "status": "トランザクションが正常に実行されたか、リバートされたか。", + "confirmations": "このトランザクション後にマイニングされたブロック数。確認数が多いほどファイナリティが高い。", + "interactedWith": "このトランザクションが呼び出したコントラクト、または単純な送金の受取アドレス。", + "transactionFee": "このトランザクションの処理に支払われた合計手数料(使用ガス × ガス価格)。", + "gasPrice": "ガス1単位あたりの価格(Gwei単位)。高いガス価格はより早い取り込みを促進します。", + "gasLimitUsage": "ガスリミットは承認された最大ガス量。使用ガスは実際に消費された量。", + "nonce": "送信者のトランザクションカウンター。トランザクションが順番に処理されることを保証します。", + "position": "ブロック内のこのトランザクションのインデックス。低い位置が先に処理されます。", + "type": "トランザクション形式(例:Legacy、EIP-1559、EIP-4844)。適用される手数料フィールドを決定します。", + "decodedInput": "コントラクトに送信された関数呼び出しとパラメータを人間が読める形式にデコードしたもの。", + "maxFeePerBlobGas": "送信者がデータ可用性のために支払うBlobガス1単位あたりの最高価格。", + "blobGasPrice": "このブロックで支払われたBlobガス1単位あたりの実際の価格。", + "blobGasUsed": "このトランザクションのデータBlobが消費したBlobガスの量。", + "blobCount": "ロールアップデータ可用性のためにこのトランザクションに添付されたデータBlobの数。", + "blobVersionedHashes": "このトランザクションがコミットした各データBlobを一意に識別するバージョン付きハッシュ。", + "contractCreated": "このトランザクションによってデプロイされた新しいコントラクトのアドレス。", + "value": "このトランザクションで送金されたネイティブ通貨(例:ETH)の金額。", + "effectiveGasPrice": "EIP-1559の手数料計算後に実際に支払われたガス価格。リクエストした価格と異なる場合があります。", + "l1BlockNumber": "このL2トランザクションのセキュリティを担保するEthereum L1ブロック。", + "gasUsedForL1": "このトランザクションのデータをEthereum L1に投稿するために消費されたガス。", + "l1Fee": "Ethereum L1でのデータ可用性に支払われた手数料。このL2の合計トランザクションコストの一部。", + "l1GasPrice": "データ可用性手数料の計算に使用されたL1ガス価格。", + "l1GasUsed": "このトランザクションのcalldataを投稿するために必要な推定L1ガス。", + "l1FeeScalar": "L2シーケンサーがL1手数料計算に適用する乗数。" + }, + "block": { + "hash": "このブロックを識別する一意のフィンガープリント。内容から導出されます。", + "transactions": "このブロックに含まれ実行されたトランザクションの数。", + "withdrawals": "このブロックで処理されたバリデーターの引き出し。ステークされたETHを返却します。", + "feeRecipient": "このブロック内のトランザクションから優先手数料を受け取るアドレス。", + "difficulty": "このブロックのマイニング難易度。マージ後のProof of Stakeネットワークでは常にゼロ。", + "totalDifficulty": "このブロックまでのチェーンの累積難易度。Proof of Workのレガシーフィールド。", + "size": "ブロックデータの合計サイズ(バイト)。", + "extraData": "ブロック生成者が設定した任意のデータ。クライアントやプールの識別子が含まれることが多い。", + "gasUsed": "このブロック内の全トランザクションで消費された合計ガス。", + "gasLimit": "このブロックで許可される最大ガス量。ブロックの容量を定義します。", + "baseFeePerGas": "このブロックの最低ガス価格。ネットワークの需要に基づいて設定されます(EIP-1559)。", + "burntFees": "EIP-1559により流通から永久に除去されたトランザクション手数料。", + "blobGasUsed": "このブロック内のBlobトランザクションが消費した合計Blobガス。", + "excessBlobGas": "目標を超えたBlobガス。次のブロックのBlob基本手数料の計算に使用されます。", + "blobCount": "ロールアップデータ可用性のためにこのブロックに含まれるデータBlobの数。", + "l1BlockNumber": "このArbitrumブロックに関連するEthereum L1ブロック番号。", + "sendCount": "このArbitrumブロックで送信されたL2からL1への送信メッセージの数。", + "sendRoot": "すべてのL2からL1への送信メッセージのMerkleルート。クロスレイヤー検証に使用されます。", + "parentHash": "チェーン内の前のブロックのハッシュ。ブロック同士をリンクします。", + "stateRoot": "このブロックの処理後のブロックチェーン全体の状態のMerkleルート。", + "transactionsRoot": "このブロックに含まれるすべてのトランザクションのMerkleルート。", + "receiptsRoot": "このブロックのすべてのトランザクションレシートのMerkleルート。", + "withdrawalsRoot": "このブロックで処理されたすべてのバリデーター引き出しのMerkleルート。", + "logsBloom": "このブロックで発行されたイベントログを効率的に検索するためのブルームフィルター。", + "nonce": "Proof of Workマイニングで使用される値。マージ後は常にゼロ。", + "mixHash": "Proof of Workアルゴリズムで使用されるハッシュ。マージ後はRANDAO値に置き換えられました。", + "sha3Uncles": "アンクルブロックリストのハッシュ。マージ後は常に空リストのハッシュ。", + "validator": "ビーコンチェーンからこの引き出しを開始したバリデーターインデックス。" + }, + "address": { + "verification": "検証済みコントラクトは、ソースコードがデプロイされたバイトコードと一致することが公開確認されています。", + "proxyType": "このコントラクトはアップグレード可能なプロキシパターンを使用しています。ロジックは別の実装コントラクトにあります。", + "readContract": "ガスを消費せず、ウォレットを接続せずにコントラクトデータを照会。読み取り専用の呼び出し。", + "writeContract": "コントラクトの状態を変更するトランザクションを送信。接続されたウォレットとガスが必要です。", + "balance": "このアドレスが保有するネイティブ通貨の残高。", + "usdValue": "現在の市場価格に基づく推定法定通貨価値。", + "nonce": "このアドレスから送信されたトランザクション数。トランザクションの順序付けに使用されます。", + "eip7702Delegate": "このアカウントはEIP-7702を介してコード実行を別のアドレスに委任しています。", + "implementationAddress": "このプロキシの実際のロジックを含むコントラクト。", + "ensName": "このアドレスに関連付けられたEthereum Name Serviceの名前。", + "ensApp": "このENS名前にリンクされたアプリケーションまたはリゾルバー。" + }, + "token": { + "tokenStandard": "トークンのインターフェース標準(ERC-20、ERC-721、ERC-1155など)。トークンの動作を定義します。", + "decimals": "トークン量の表示に使用される小数点以下の桁数。ほとんどのERC-20トークンは18桁を使用します。", + "totalSupply": "このコントラクトで作成されたトークンの総数。", + "tokenId": "コレクション内のこの特定のトークンを識別する一意の数値。", + "owner": "現在このNFTを保有しているアドレス。", + "approved": "所有者に代わってこの特定のNFTを転送する権限を持つアドレス。", + "metadataUri": "このトークンのメタデータ(名前、画像、属性)が保存されているURI。" + }, + "bitcoin": { + "txid": "このトランザクションの一意の識別子。シリアライズされたデータから計算されます。", + "witnessHash": "ウィットネス(SegWit)データを含むトランザクションハッシュ。SegWitトランザクションではTXIDと異なります。", + "block": "このトランザクションを含むブロック。", + "status": "このトランザクションがブロックで確認されたか、まだメモリプールで待機中か。", + "inputs": "使用される以前の出力の数。各入力はUTXOを参照します。", + "outputs": "作成される新しい出力の数。各出力はBTCをアドレスにロックします。", + "fee": "入力合計と出力合計の差額。マイナーに支払われます。", + "feePerByte": "生のトランザクションデータ1バイトあたりの手数料率(satoshi)。", + "feePerVByte": "仮想バイトあたりの手数料率(satoshi)。SegWitトランザクションの標準的な手数料指標。", + "feePerWU": "重量単位あたりの手数料率(satoshi)。最も細かい手数料指標。", + "size": "ウィットネスデータを含む生のトランザクションサイズ(バイト)。", + "virtualSize": "ウィットネスデータを割引した調整済みトランザクションサイズ。手数料計算に使用。", + "weight": "トランザクションの重量(重量単位WU)。1 vByte = 4 WU。", + "coinbase": "これがブロック報酬として新しいBTCを作成するコインベーストランザクションかどうか。", + "witness": "このトランザクションがSegregated Witness(SegWit)フォーマットを使用しているかどうか。", + "rbf": "Replace-By-Fee。有効な場合、確認前により高い手数料のトランザクションで置き換え可能。", + "version": "トランザクションフォーマットのバージョン番号。利用可能な機能を決定します。", + "locktime": "このトランザクションがブロックに含められる最も早いブロック高さまたは時刻。", + "blockHash": "このトランザクションを含むブロックを識別する一意のハッシュ。", + "minedBy": "このブロックを生成したマイニングプールまたはエンティティ。", + "blockReward": "このブロックのマイニング報酬として作成された新しいBTC(補助金+手数料)。", + "totalFees": "このブロックでマイナーが徴収した全トランザクション手数料の合計。", + "feeRate": "このブロック内のトランザクションの平均および中央値の手数料率。", + "transactions": "このブロックに含まれるトランザクションの数。", + "totalOutput": "このブロックで作成されたすべての出力のBTC総額。", + "difficulty": "有効なブロックハッシュを見つける難しさ。2016ブロックごとに調整。", + "blockSize": "シリアライズされたブロックデータの合計サイズ。", + "blockWeight": "ブロックの重量(重量単位)。最大4,000,000 WU。", + "previousBlock": "前のブロックのハッシュ。このブロックをチェーンにリンクします。", + "nextBlock": "次のブロックのハッシュ(存在する場合)。", + "coinbaseMessage": "マイナーがコインベーストランザクションに埋め込んだ任意のテキスト。", + "merkleRoot": "このブロック内の全トランザクションのMerkleツリーのルートハッシュ。", + "blockVersion": "ブロックフォーマットのバージョン。どのコンセンサスルールとソフトフォークがシグナルされるかをエンコード。", + "bits": "有効なブロックハッシュのターゲット閾値のコンパクトエンコーディング。", + "blockNonce": "マイナーがターゲット以下のブロックハッシュを見つけるために反復する値。", + "coinbaseHex": "コインベーストランザクション入力の生の16進数データ。", + "address": "公開鍵から導出されたBitcoinアドレス。BTCの受け取りに使用。", + "balance": "このアドレスが全未使用出力にわたって保有するBTC合計。", + "totalReceived": "このアドレスが全トランザクションにわたって受け取った累計BTC。", + "utxos": "未使用トランザクション出力。このアドレスが使用可能な個別のコイン。", + "txCount": "このアドレスに関連するトランザクションの総数。" + }, + "settings": { + "knowledgeLevel": "エクスプローラー全体で表示される説明ヘルプの量を制御します。" + } +} diff --git a/src/locales/pt-BR/common.json b/src/locales/pt-BR/common.json index 63f1eae8..e73d46f5 100644 --- a/src/locales/pt-BR/common.json +++ b/src/locales/pt-BR/common.json @@ -26,7 +26,14 @@ "disableSuperUser": "Desativar Modo Super Usuário", "enableSuperUser": "Ativar Modo Super Usuário", "mempool": "Mempool", - "txs": "Transações" + "txs": "Transações", + "tooltipsBeginner": "Dicas: Iniciante", + "tooltipsIntermediate": "Dicas: Intermediário", + "tooltipsAdvanced": "Dicas: Avançado", + "tooltipsSwitched": "Nível de dicas alterado para {{level}}", + "tooltipsLevelBeginner": "Iniciante", + "tooltipsLevelIntermediate": "Intermediário", + "tooltipsLevelAdvanced": "Avançado" }, "footer": { "about": "Sobre", diff --git a/src/locales/pt-BR/settings.json b/src/locales/pt-BR/settings.json index eac0b08d..88ec23e9 100644 --- a/src/locales/pt-BR/settings.json +++ b/src/locales/pt-BR/settings.json @@ -149,6 +149,21 @@ } } }, + "helperTooltips": { + "title": "Dicas de Ajuda", + "description": "Mostrar ajuda contextual para campos de dados blockchain.", + "enabled": { + "label": "Mostrar Dicas de Ajuda", + "description": "Exibir ícones de ajuda ao lado dos rótulos com explicações breves." + }, + "knowledgeLevel": { + "label": "Nível de Conhecimento", + "description": "Controla quantas dicas de ajuda são exibidas. Iniciante mostra mais, Avançado mostra menos.", + "beginner": "Iniciante", + "intermediate": "Intermediário", + "advanced": "Avançado" + } + }, "rpcEndpoints": { "title": "Endpoints RPC", "description": "Configure URLs RPC para cada rede. Clique em uma rede para expandir e configurar seus endpoints.", diff --git a/src/locales/pt-BR/tooltips.json b/src/locales/pt-BR/tooltips.json new file mode 100644 index 00000000..4fe7de03 --- /dev/null +++ b/src/locales/pt-BR/tooltips.json @@ -0,0 +1,128 @@ +{ + "transaction": { + "hash": "Um identificador único para esta transação, gerado a partir de seu conteúdo.", + "from": "O endereço que iniciou e assinou esta transação.", + "status": "Se a transação foi executada com sucesso ou revertida.", + "confirmations": "Blocos minerados após esta transação. Mais confirmações significa maior finalidade.", + "interactedWith": "O contrato com o qual esta transação interagiu, ou o endereço do destinatário em transferências simples.", + "transactionFee": "Taxa total paga para processar esta transação (gas usado × preço do gas).", + "gasPrice": "Preço por unidade de gas, em Gwei. Preços mais altos incentivam inclusão mais rápida.", + "gasLimitUsage": "O limite de gas é o máximo autorizado. O gas usado é a quantidade real consumida.", + "nonce": "Contador de transações do remetente. Garante que as transações sejam processadas em ordem.", + "position": "O índice desta transação dentro do seu bloco. Posições mais baixas foram processadas primeiro.", + "type": "O formato da transação (ex: Legacy, EIP-1559, EIP-4844). Determina quais campos de taxa se aplicam.", + "decodedInput": "A chamada de função e parâmetros enviados ao contrato, decodificados em formato legível.", + "maxFeePerBlobGas": "Preço máximo por unidade de blob gas que o remetente está disposto a pagar pela disponibilidade de dados.", + "blobGasPrice": "Preço real por unidade de blob gas pago neste bloco.", + "blobGasUsed": "Quantidade de blob gas consumido pelos blobs de dados desta transação.", + "blobCount": "Número de blobs de dados anexados a esta transação para disponibilidade de dados de rollup.", + "blobVersionedHashes": "Hashes versionados que identificam exclusivamente cada blob de dados comprometido por esta transação.", + "contractCreated": "O endereço do novo contrato implantado por esta transação.", + "value": "Quantidade de moeda nativa (ex: ETH) transferida nesta transação.", + "effectiveGasPrice": "O preço de gas realmente pago após o cálculo de taxa EIP-1559, que pode diferir do preço solicitado.", + "l1BlockNumber": "O bloco Ethereum L1 que ancora esta transação L2 para segurança.", + "gasUsedForL1": "Gas consumido para publicar os dados desta transação no Ethereum L1.", + "l1Fee": "Taxa paga pela disponibilidade de dados no Ethereum L1. Parte do custo total da transação nesta L2.", + "l1GasPrice": "O preço de gas L1 usado para calcular o componente de taxa de disponibilidade de dados.", + "l1GasUsed": "Gas L1 estimado necessário para publicar o calldata desta transação.", + "l1FeeScalar": "Um multiplicador aplicado ao cálculo da taxa L1 pelo sequenciador L2." + }, + "block": { + "hash": "Uma impressão digital única que identifica este bloco, derivada de seu conteúdo.", + "transactions": "O número de transações incluídas e executadas neste bloco.", + "withdrawals": "Saques de validadores processados neste bloco, retornando ETH em stake.", + "feeRecipient": "O endereço que recebe as taxas prioritárias das transações neste bloco.", + "difficulty": "Dificuldade de mineração para este bloco. Sempre zero em redes proof-of-stake após o Merge.", + "totalDifficulty": "Dificuldade acumulada da cadeia até este bloco. Campo legado de proof-of-work.", + "size": "O tamanho total dos dados do bloco em bytes.", + "extraData": "Dados arbitrários definidos pelo produtor do bloco. Frequentemente contém identificadores de cliente ou pool.", + "gasUsed": "Gas total consumido por todas as transações neste bloco.", + "gasLimit": "Gas máximo permitido neste bloco, definindo sua capacidade.", + "baseFeePerGas": "Preço mínimo de gas para este bloco, definido pela rede com base na demanda (EIP-1559).", + "burntFees": "Taxas de transação permanentemente removidas de circulação via EIP-1559.", + "blobGasUsed": "Blob gas total consumido por transações blob neste bloco.", + "excessBlobGas": "Blob gas acima do alvo, usado para calcular a taxa base blob do próximo bloco.", + "blobCount": "Número de blobs de dados incluídos neste bloco para disponibilidade de dados de rollup.", + "l1BlockNumber": "O número do bloco Ethereum L1 associado a este bloco Arbitrum.", + "sendCount": "Número de mensagens de saída L2-para-L1 enviadas neste bloco Arbitrum.", + "sendRoot": "Raiz de Merkle de todas as mensagens de saída L2-para-L1, usada para verificação entre camadas.", + "parentHash": "Hash do bloco anterior na cadeia, ligando os blocos entre si.", + "stateRoot": "Raiz de Merkle de todo o estado da blockchain após processar este bloco.", + "transactionsRoot": "Raiz de Merkle de todas as transações incluídas neste bloco.", + "receiptsRoot": "Raiz de Merkle de todos os recibos de transações deste bloco.", + "withdrawalsRoot": "Raiz de Merkle de todos os saques de validadores processados neste bloco.", + "logsBloom": "Um filtro bloom para buscar eficientemente logs de eventos emitidos neste bloco.", + "nonce": "Um valor usado na mineração proof-of-work. Sempre zero após o Merge.", + "mixHash": "Um hash usado no algoritmo proof-of-work. Substituído pelo valor RANDAO após o Merge.", + "sha3Uncles": "Hash da lista de blocos uncle. Sempre o hash de lista vazia após o Merge.", + "validator": "O índice do validador que iniciou esta retirada da beacon chain." + }, + "address": { + "verification": "Um contrato verificado tem seu código-fonte publicamente confirmado como correspondente ao bytecode implantado.", + "proxyType": "Este contrato usa um padrão de proxy atualizável. A lógica está em um contrato de implementação separado.", + "readContract": "Consultar dados do contrato sem gastar gas ou conectar uma carteira. Chamadas somente leitura.", + "writeContract": "Enviar uma transação que altera o estado do contrato. Requer uma carteira conectada e gas.", + "balance": "Saldo de moeda nativa mantido por este endereço.", + "usdValue": "Valor fiduciário estimado com base no preço de mercado atual.", + "nonce": "Número de transações enviadas a partir deste endereço. Usado para ordenação de transações.", + "eip7702Delegate": "Esta conta delega a execução de seu código a outro endereço via EIP-7702.", + "implementationAddress": "O contrato que contém a lógica real deste proxy.", + "ensName": "Nome do Ethereum Name Service associado a este endereço.", + "ensApp": "Aplicação ou resolvedor vinculado a este nome ENS." + }, + "token": { + "tokenStandard": "O padrão de interface do token (ex: ERC-20, ERC-721, ERC-1155) que define como este token se comporta.", + "decimals": "Número de casas decimais usadas para exibir quantidades do token. A maioria dos tokens ERC-20 usa 18.", + "totalSupply": "Número total de tokens criados para este contrato.", + "tokenId": "Um identificador numérico único para este token específico dentro de sua coleção.", + "owner": "O endereço que atualmente possui este NFT.", + "approved": "Um endereço autorizado a transferir este NFT específico em nome do proprietário.", + "metadataUri": "A URI onde os metadados deste token (nome, imagem, atributos) estão armazenados." + }, + "bitcoin": { + "txid": "Um identificador único para esta transação, calculado a partir de seus dados serializados.", + "witnessHash": "Hash da transação incluindo dados witness (SegWit). Difere do TXID para transações SegWit.", + "block": "O bloco que inclui esta transação.", + "status": "Se esta transação foi confirmada em um bloco ou ainda está esperando no mempool.", + "inputs": "O número de saídas anteriores sendo gastas. Cada entrada referencia um UTXO.", + "outputs": "O número de novas saídas criadas. Cada saída bloqueia BTC para um endereço.", + "fee": "A diferença entre entradas e saídas totais, paga ao minerador.", + "feePerByte": "Taxa de tarifa em satoshis por byte de dados brutos da transação.", + "feePerVByte": "Taxa de tarifa em satoshis por byte virtual. A métrica padrão para transações SegWit.", + "feePerWU": "Taxa de tarifa em satoshis por unidade de peso. A métrica de tarifa mais granular.", + "size": "Tamanho bruto da transação em bytes, incluindo dados witness.", + "virtualSize": "Tamanho ajustado que desconta dados witness. Usado para cálculo de taxas.", + "weight": "Peso da transação em unidades de peso (WU). 1 vByte = 4 WU.", + "coinbase": "Se esta é uma transação coinbase que cria novos BTC como recompensa de bloco.", + "witness": "Se esta transação usa o formato Segregated Witness (SegWit).", + "rbf": "Replace-By-Fee. Se habilitado, esta transação pode ser substituída por uma com taxa maior antes da confirmação.", + "version": "Número de versão do formato da transação. Determina quais recursos estão disponíveis.", + "locktime": "Altura de bloco ou momento mais cedo em que esta transação pode ser incluída em um bloco.", + "blockHash": "O hash único que identifica o bloco que contém esta transação.", + "minedBy": "O pool de mineração ou entidade que produziu este bloco.", + "blockReward": "Novos BTC criados como recompensa por minerar este bloco (subsídio + taxas).", + "totalFees": "Soma de todas as taxas de transação coletadas pelo minerador neste bloco.", + "feeRate": "Taxas de tarifa média e mediana das transações neste bloco.", + "transactions": "Número de transações incluídas neste bloco.", + "totalOutput": "Valor total de BTC de todas as saídas criadas neste bloco.", + "difficulty": "Quão difícil é encontrar um hash de bloco válido. Ajusta a cada 2016 blocos.", + "blockSize": "Tamanho total dos dados serializados do bloco.", + "blockWeight": "Peso do bloco em unidades de peso. Máximo: 4.000.000 WU.", + "previousBlock": "Hash do bloco anterior, ligando este bloco à cadeia.", + "nextBlock": "Hash do bloco seguinte, se existir.", + "coinbaseMessage": "Texto arbitrário incorporado na transação coinbase pelo minerador.", + "merkleRoot": "Hash raiz da árvore de Merkle de todas as transações neste bloco.", + "blockVersion": "Versão do formato do bloco. Codifica quais regras de consenso e soft forks são sinalizados.", + "bits": "Codificação compacta do limiar alvo para um hash de bloco válido.", + "blockNonce": "Um valor que mineradores iteram para encontrar um hash de bloco abaixo do alvo.", + "coinbaseHex": "Dados hexadecimais brutos da entrada da transação coinbase.", + "address": "Um endereço Bitcoin derivado de uma chave pública, usado para receber BTC.", + "balance": "BTC total mantido por este endereço em todas as saídas não gastas.", + "totalReceived": "BTC cumulativo recebido por este endereço em todas as transações.", + "utxos": "Saídas de Transação Não Gastas. Moedas individuais disponíveis para gasto por este endereço.", + "txCount": "Número total de transações envolvendo este endereço." + }, + "settings": { + "knowledgeLevel": "Controla quanta ajuda explicativa é exibida no explorador." + } +} diff --git a/src/locales/zh/common.json b/src/locales/zh/common.json index 188bbfae..201b44af 100644 --- a/src/locales/zh/common.json +++ b/src/locales/zh/common.json @@ -26,7 +26,14 @@ "disableSuperUser": "禁用超级用户模式", "enableSuperUser": "启用超级用户模式", "mempool": "内存池", - "txs": "交易" + "txs": "交易", + "tooltipsBeginner": "提示:初学者", + "tooltipsIntermediate": "提示:中级", + "tooltipsAdvanced": "提示:高级", + "tooltipsSwitched": "提示帮助级别已切换为{{level}}", + "tooltipsLevelBeginner": "初学者", + "tooltipsLevelIntermediate": "中级", + "tooltipsLevelAdvanced": "高级" }, "footer": { "about": "关于", diff --git a/src/locales/zh/settings.json b/src/locales/zh/settings.json index 91216afd..c880864f 100644 --- a/src/locales/zh/settings.json +++ b/src/locales/zh/settings.json @@ -149,6 +149,21 @@ } } }, + "helperTooltips": { + "title": "帮助提示", + "description": "为区块链数据字段显示上下文帮助。", + "enabled": { + "label": "显示帮助提示", + "description": "在字段标签旁显示帮助图标和简要说明。" + }, + "knowledgeLevel": { + "label": "知识水平", + "description": "控制显示多少帮助提示。初学者显示最多,高级显示最少。", + "beginner": "初学者", + "intermediate": "中级", + "advanced": "高级" + } + }, "rpcEndpoints": { "title": "RPC 端点", "description": "为每个网络配置 RPC URL。点击网络展开并配置其端点。", diff --git a/src/locales/zh/tooltips.json b/src/locales/zh/tooltips.json new file mode 100644 index 00000000..9136700b --- /dev/null +++ b/src/locales/zh/tooltips.json @@ -0,0 +1,128 @@ +{ + "transaction": { + "hash": "此交易的唯一标识符,由其内容生成。", + "from": "发起并签署此交易的地址。", + "status": "交易是否成功执行或已回滚。", + "confirmations": "此交易之后挖出的区块数。更多确认意味着更高的最终性。", + "interactedWith": "此交易调用的合约,或简单转账的接收地址。", + "transactionFee": "处理此交易支付的总费用(使用的Gas × Gas价格)。", + "gasPrice": "每单位Gas的价格,以Gwei为单位。更高的Gas价格可以更快被打包。", + "gasLimitUsage": "Gas限制是授权的最大Gas量。已用Gas是实际消耗的量。", + "nonce": "发送者的交易计数器。确保交易按顺序处理。", + "position": "此交易在区块中的索引。较低的位置优先处理。", + "type": "交易格式(如Legacy、EIP-1559、EIP-4844)。决定适用哪些费用字段。", + "decodedInput": "发送给合约的函数调用和参数,解码为可读格式。", + "maxFeePerBlobGas": "发送者愿意为数据可用性支付的每单位Blob Gas最高价格。", + "blobGasPrice": "此区块中实际支付的每单位Blob Gas价格。", + "blobGasUsed": "此交易的数据Blob消耗的Blob Gas量。", + "blobCount": "附加到此交易的数据Blob数量,用于Rollup数据可用性。", + "blobVersionedHashes": "唯一标识此交易提交的每个数据Blob的版本化哈希。", + "contractCreated": "此交易部署的新合约地址。", + "value": "此交易中转移的原生货币(如ETH)金额。", + "effectiveGasPrice": "经EIP-1559费用计算后实际支付的Gas价格,可能与请求的价格不同。", + "l1BlockNumber": "锚定此L2交易安全性的以太坊L1区块。", + "gasUsedForL1": "将此交易数据发布到以太坊L1所消耗的Gas。", + "l1Fee": "在以太坊L1上为数据可用性支付的费用。是此L2上总交易成本的一部分。", + "l1GasPrice": "用于计算数据可用性费用的L1 Gas价格。", + "l1GasUsed": "发布此交易calldata所需的预估L1 Gas。", + "l1FeeScalar": "L2排序器应用于L1费用计算的乘数。" + }, + "block": { + "hash": "标识此区块的唯一指纹,由其内容派生。", + "transactions": "此区块中包含和执行的交易数量。", + "withdrawals": "此区块中处理的验证者提款,返回质押的ETH。", + "feeRecipient": "接收此区块中交易优先费用的地址。", + "difficulty": "此区块的挖矿难度。在合并后的权益证明网络上始终为零。", + "totalDifficulty": "到此区块为止的链累积难度。工作量证明的遗留字段。", + "size": "区块数据的总大小(字节)。", + "extraData": "区块生产者设置的任意数据。通常包含客户端或矿池标识符。", + "gasUsed": "此区块中所有交易消耗的总Gas。", + "gasLimit": "此区块允许的最大Gas量,定义其容量。", + "baseFeePerGas": "此区块的最低Gas价格,由网络根据需求设定(EIP-1559)。", + "burntFees": "通过EIP-1559永久从流通中移除的交易费用。", + "blobGasUsed": "此区块中Blob交易消耗的总Blob Gas。", + "excessBlobGas": "超出目标的Blob Gas,用于计算下一个区块的Blob基础费用。", + "blobCount": "此区块中包含的数据Blob数量,用于Rollup数据可用性。", + "l1BlockNumber": "与此Arbitrum区块关联的以太坊L1区块号。", + "sendCount": "此Arbitrum区块中发送的L2到L1出站消息数量。", + "sendRoot": "所有L2到L1出站消息的Merkle根,用于跨层验证。", + "parentHash": "链中前一个区块的哈希,将区块链接在一起。", + "stateRoot": "处理此区块后整个区块链状态的Merkle根。", + "transactionsRoot": "此区块中包含的所有交易的Merkle根。", + "receiptsRoot": "此区块中所有交易收据的Merkle根。", + "withdrawalsRoot": "此区块中处理的所有验证者提款的Merkle根。", + "logsBloom": "用于高效搜索此区块中发出的事件日志的布隆过滤器。", + "nonce": "工作量证明挖矿中使用的值。合并后始终为零。", + "mixHash": "工作量证明算法中使用的哈希。合并后被RANDAO值替代。", + "sha3Uncles": "叔块列表的哈希。合并后始终为空列表哈希。", + "validator": "从信标链发起此提款的验证者索引。" + }, + "address": { + "verification": "已验证的合约其源代码已被公开确认与部署的字节码匹配。", + "proxyType": "此合约使用可升级代理模式。逻辑位于单独的实现合约中。", + "readContract": "查询合约数据,无需消耗Gas或连接钱包。只读调用。", + "writeContract": "发送改变合约状态的交易。需要连接钱包并消耗Gas。", + "balance": "此地址持有的原生货币余额。", + "usdValue": "基于当前市场价格的预估法币价值。", + "nonce": "从此地址发送的交易数量。用于交易排序。", + "eip7702Delegate": "此账户通过EIP-7702将其代码执行委托给另一个地址。", + "implementationAddress": "包含此代理实际逻辑的合约。", + "ensName": "与此地址关联的以太坊名称服务名称。", + "ensApp": "与此ENS名称关联的应用或解析器。" + }, + "token": { + "tokenStandard": "代币接口标准(如ERC-20、ERC-721、ERC-1155),定义了代币的行为方式。", + "decimals": "用于显示代币数量的小数位数。大多数ERC-20代币使用18位小数。", + "totalSupply": "为此合约创建的代币总数。", + "tokenId": "此特定代币在其集合中的唯一数字标识符。", + "owner": "当前持有此NFT的地址。", + "approved": "被授权代表所有者转移此特定NFT的地址。", + "metadataUri": "存储此代币元数据(名称、图片、属性)的URI。" + }, + "bitcoin": { + "txid": "此交易的唯一标识符,由其序列化数据计算得出。", + "witnessHash": "包含见证(SegWit)数据的交易哈希。对于SegWit交易与TXID不同。", + "block": "包含此交易的区块。", + "status": "此交易是否已在区块中确认,或仍在内存池中等待。", + "inputs": "正在花费的先前输出数量。每个输入引用一个UTXO。", + "outputs": "创建的新输出数量。每个输出将BTC锁定到一个地址。", + "fee": "总输入与总输出之间的差额,支付给矿工。", + "feePerByte": "每字节原始交易数据的费率(聪)。", + "feePerVByte": "每虚拟字节的费率(聪)。SegWit交易的标准费率指标。", + "feePerWU": "每重量单位的费率(聪)。最精细的费率指标。", + "size": "原始交易大小(字节),包括见证数据。", + "virtualSize": "折扣见证数据后的调整交易大小。用于费用计算。", + "weight": "交易重量(重量单位WU)。1 vByte = 4 WU。", + "coinbase": "这是否是创建新BTC作为区块奖励的coinbase交易。", + "witness": "此交易是否使用隔离见证(SegWit)格式。", + "rbf": "费用替换。如果启用,此交易可在确认前被更高费用的交易替换。", + "version": "交易格式版本号。决定可用的功能。", + "locktime": "此交易可被包含在区块中的最早区块高度或时间。", + "blockHash": "标识包含此交易的区块的唯一哈希。", + "minedBy": "产生此区块的矿池或实体。", + "blockReward": "挖出此区块的奖励新BTC(补贴+费用)。", + "totalFees": "矿工在此区块中收取的所有交易费用总和。", + "feeRate": "此区块中交易的平均和中位费率。", + "transactions": "此区块中包含的交易数量。", + "totalOutput": "此区块中创建的所有输出的BTC总值。", + "difficulty": "找到有效区块哈希的难度。每2016个区块调整一次。", + "blockSize": "序列化区块数据的总大小。", + "blockWeight": "区块重量(重量单位)。最大4,000,000 WU。", + "previousBlock": "前一个区块的哈希,将此区块链接到链上。", + "nextBlock": "下一个区块的哈希(如果存在)。", + "coinbaseMessage": "矿工在coinbase交易中嵌入的任意文本。", + "merkleRoot": "此区块中所有交易的Merkle树根哈希。", + "blockVersion": "区块格式版本。编码信号哪些共识规则和软分叉。", + "bits": "有效区块哈希目标阈值的紧凑编码。", + "blockNonce": "矿工迭代以找到低于目标的区块哈希的值。", + "coinbaseHex": "coinbase交易输入的原始十六进制数据。", + "address": "从公钥派生的比特币地址,用于接收BTC。", + "balance": "此地址在所有未花费输出中持有的BTC总量。", + "totalReceived": "此地址在所有交易中累计收到的BTC。", + "utxos": "未花费交易输出。此地址可用于花费的单个币。", + "txCount": "涉及此地址的交易总数。" + }, + "settings": { + "knowledgeLevel": "控制整个浏览器中显示的帮助说明数量。" + } +} diff --git a/src/styles/helper-tooltip.css b/src/styles/helper-tooltip.css new file mode 100644 index 00000000..1a6d6305 --- /dev/null +++ b/src/styles/helper-tooltip.css @@ -0,0 +1,128 @@ +/* ===== Helper Tooltip ===== */ + +.helper-tooltip { + position: relative; + display: inline-flex; + align-items: center; +} + +/* Trigger button */ +.helper-tooltip-trigger { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; + margin-left: 5px; + background: none; + border: none; + cursor: pointer; + color: var(--text-tertiary); + opacity: 0.6; + transition: opacity 0.15s ease, color 0.15s ease; + vertical-align: middle; + line-height: 1; + flex-shrink: 0; +} + +.helper-tooltip-trigger:hover, +.helper-tooltip-trigger:focus-visible { + opacity: 1; + color: var(--color-info); + outline: none; +} + +.helper-tooltip-trigger:focus-visible { + outline: 2px solid var(--color-info); + outline-offset: 2px; + border-radius: 50%; +} + +/* Tooltip bubble */ +.helper-tooltip-bubble { + position: absolute; + left: 50%; + transform: translateX(-50%); + max-width: 260px; + min-width: 140px; + padding: 8px 12px; + background: var(--bg-tooltip); + color: #fff; + font-size: 0.8rem; + font-weight: 400; + line-height: 1.45; + border-radius: 6px; + box-shadow: var(--shadow-md); + z-index: 1000; + pointer-events: auto; + white-space: normal; + word-wrap: break-word; +} + +/* Top placement (default) */ +.helper-tooltip-top { + bottom: calc(100% + 6px); +} + +.helper-tooltip-top::after { + content: ""; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + border-width: 5px; + border-style: solid; + border-color: var(--bg-tooltip) transparent transparent transparent; +} + +/* Bottom placement */ +.helper-tooltip-bottom { + top: calc(100% + 6px); +} + +.helper-tooltip-bottom::after { + content: ""; + position: absolute; + bottom: 100%; + left: 50%; + transform: translateX(-50%); + border-width: 5px; + border-style: solid; + border-color: transparent transparent var(--bg-tooltip) transparent; +} + +/* Light theme text: keep tooltip text white since bg-tooltip is dark in both themes */ +.light-theme .helper-tooltip-bubble { + color: #fff; +} + +/* ===== Navbar Tooltip Level Button ===== */ + +.navbar-toggle-btn.navbar-tooltip-level-beginner { + border-color: var(--color-primary-muted); +} + +.navbar-toggle-btn.navbar-tooltip-level-intermediate { + border-color: var(--color-info); +} + +.navbar-toggle-btn.navbar-tooltip-level-advanced { + border-color: var(--color-accent); +} + +/* Mobile adjustments */ +@media (max-width: 767px) { + .helper-tooltip-bubble { + max-width: 220px; + font-size: 0.78rem; + left: auto; + right: -8px; + transform: none; + } + + .helper-tooltip-top::after, + .helper-tooltip-bottom::after { + left: auto; + right: 12px; + transform: none; + } +} diff --git a/src/styles/styles.css b/src/styles/styles.css index 44b02a46..84c804e8 100644 --- a/src/styles/styles.css +++ b/src/styles/styles.css @@ -2478,7 +2478,8 @@ a.navbar-logo-dropdown-item:hover { } .notification { - width: clamp(240px, 90vw, 520px); + width: fit-content; + max-width: clamp(240px, 90vw, 520px); padding: 14px 18px; border-radius: 12px; box-shadow: 0 4px 14px -2px rgba(0, 0, 0, 0.2); diff --git a/src/types/index.ts b/src/types/index.ts index 169da421..c7b1be33 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -483,6 +483,11 @@ export type AIAnalysisType = */ export type PromptVersion = "stable" | "latest"; +/** + * Knowledge level for helper tooltip visibility + */ +export type KnowledgeLevel = "beginner" | "intermediate" | "advanced"; + /** * User settings for the application */ @@ -495,6 +500,8 @@ export interface UserSettings { isSuperUser?: boolean; promptVersion?: PromptVersion; persistentCacheSizeMB?: number; + knowledgeLevel?: KnowledgeLevel; + showHelperTooltips?: boolean; } /** @@ -509,6 +516,8 @@ export const DEFAULT_SETTINGS: UserSettings = { isSuperUser: false, promptVersion: "stable", persistentCacheSizeMB: 10, + knowledgeLevel: "beginner", + showHelperTooltips: true, }; /** From e4e1238a10315c6850a6ceb1b21e7ef64b7b1a84 Mon Sep 17 00:00:00 2001 From: Augusto Lemble Date: Thu, 19 Mar 2026 12:06:21 -0300 Subject: [PATCH 2/7] feat(tooltips): address PR #326 review feedback - Fix tooltip z-index clipping by rendering bubbles via React Portal to document.body, escaping all ancestor overflow containers - Enrich tooltip descriptions with EIP-1559, EIP-4844, UTXO model, Merkle tree, and proxy pattern explanations across all 5 locales - Fix Arbitrum difficulty tooltip and circular blob definition - Add missing tooltips: tx history table headers, account type, analyser tabs, finalized badge, contract details, Bitcoin confirmations, inputs/outputs columns, network stats, state changes - Reclassify knowledge levels: beginner=all tooltips, intermediate=hides basic fields, advanced=complex/chain-specific only - Update knowledge level descriptions in all locale settings files --- src/components/common/HelperTooltip.tsx | 74 +++++++++++--- .../pages/bitcoin/BitcoinAddressDisplay.tsx | 2 +- .../pages/bitcoin/BitcoinBlockDisplay.tsx | 40 ++++---- .../bitcoin/BitcoinTransactionDisplay.tsx | 35 +++++-- .../address/shared/AccountMoreInfoCard.tsx | 4 +- .../address/shared/AccountOverviewCard.tsx | 2 +- .../evm/address/shared/AddressHeader.tsx | 11 ++- .../evm/address/shared/ContractDetails.tsx | 19 +++- .../evm/address/shared/ContractInfoCard.tsx | 4 +- .../address/shared/ContractInteraction.tsx | 7 +- .../address/shared/ContractMoreInfoCard.tsx | 4 +- .../address/shared/NFTCollectionInfoCard.tsx | 4 +- .../evm/address/shared/TransactionHistory.tsx | 55 +++++++++-- .../pages/evm/block/BlockDisplay.tsx | 97 +++++++++---------- .../pages/evm/network/DashboardStats.tsx | 18 +++- .../pages/evm/network/NetworkStatsDisplay.tsx | 31 +++++- .../evm/tokenDetails/ERC1155TokenDisplay.tsx | 2 +- .../evm/tokenDetails/ERC721TokenDisplay.tsx | 2 +- .../pages/evm/tx/TransactionDisplay.tsx | 26 ++--- src/components/pages/evm/tx/TxAnalyser.tsx | 11 ++- .../pages/evm/tx/analyser/StateChangesTab.tsx | 28 +++++- src/locales/en/settings.json | 2 +- src/locales/en/tooltips.json | 69 +++++++++---- src/locales/es/settings.json | 2 +- src/locales/es/tooltips.json | 69 +++++++++---- src/locales/ja/settings.json | 2 +- src/locales/ja/tooltips.json | 69 +++++++++---- src/locales/pt-BR/settings.json | 2 +- src/locales/pt-BR/tooltips.json | 69 +++++++++---- src/locales/zh/settings.json | 2 +- src/locales/zh/tooltips.json | 69 +++++++++---- src/styles/helper-tooltip.css | 49 +--------- 32 files changed, 594 insertions(+), 286 deletions(-) diff --git a/src/components/common/HelperTooltip.tsx b/src/components/common/HelperTooltip.tsx index 35a52174..53e1a55a 100644 --- a/src/components/common/HelperTooltip.tsx +++ b/src/components/common/HelperTooltip.tsx @@ -1,4 +1,5 @@ -import { useCallback, useEffect, useId, useRef, useState } from "react"; +import { useCallback, useEffect, useId, useLayoutEffect, useRef, useState } from "react"; +import { createPortal } from "react-dom"; interface HelperTooltipProps { content: string; @@ -11,6 +12,7 @@ const HOVER_DELAY_MS = 350; const HelperTooltip: React.FC = ({ content, placement = "top", className }) => { const [isVisible, setIsVisible] = useState(false); const [actualPlacement, setActualPlacement] = useState(placement); + const [triggerRect, setTriggerRect] = useState(null); const tooltipId = useId(); const triggerRef = useRef(null); const bubbleRef = useRef(null); @@ -21,6 +23,7 @@ const HelperTooltip: React.FC = ({ content, placement = "top if (triggerRef.current) { const rect = triggerRef.current.getBoundingClientRect(); setActualPlacement(rect.top < 80 ? "bottom" : placement); + setTriggerRect(rect); } setIsVisible(true); }, [placement]); @@ -45,7 +48,6 @@ const HelperTooltip: React.FC = ({ content, placement = "top const handlePointerLeave = useCallback(() => { isPointerInsideRef.current = false; clearHoverTimeout(); - // Small delay to allow moving from trigger to bubble hoverTimeoutRef.current = setTimeout(() => { if (!isPointerInsideRef.current) { hide(); @@ -70,7 +72,6 @@ const HelperTooltip: React.FC = ({ content, placement = "top [hide], ); - // Touch: tap to toggle const handleClick = useCallback(() => { if (isVisible) { hide(); @@ -79,7 +80,7 @@ const HelperTooltip: React.FC = ({ content, placement = "top } }, [isVisible, show, hide]); - // Close on outside click (touch devices) + // Close on outside click useEffect(() => { if (!isVisible) return; @@ -112,6 +113,58 @@ const HelperTooltip: React.FC = ({ content, placement = "top }; }, []); + // Clamp bubble within viewport after render + useLayoutEffect(() => { + if (!isVisible || !bubbleRef.current) return; + const bubble = bubbleRef.current; + const rect = bubble.getBoundingClientRect(); + const margin = 8; + + if (rect.right > window.innerWidth - margin) { + bubble.style.left = `${window.innerWidth - margin - rect.width}px`; + bubble.style.transform = "none"; + } + if (rect.left < margin) { + bubble.style.left = `${margin}px`; + bubble.style.transform = "none"; + } + }, [isVisible, triggerRect]); + + const getBubbleStyle = (): React.CSSProperties => { + if (!triggerRect) return {}; + const gap = 6; + const centerX = triggerRect.left + triggerRect.width / 2; + + if (actualPlacement === "bottom") { + return { + position: "fixed", + top: triggerRect.bottom + gap, + left: centerX, + transform: "translateX(-50%)", + }; + } + return { + position: "fixed", + top: triggerRect.top - gap, + left: centerX, + transform: "translate(-50%, -100%)", + }; + }; + + const bubble = isVisible ? ( + + ) : null; + return ( - {isVisible && ( - - )} + {bubble && createPortal(bubble, document.body)} ); }; diff --git a/src/components/pages/bitcoin/BitcoinAddressDisplay.tsx b/src/components/pages/bitcoin/BitcoinAddressDisplay.tsx index bd4e8481..e9367f22 100644 --- a/src/components/pages/bitcoin/BitcoinAddressDisplay.tsx +++ b/src/components/pages/bitcoin/BitcoinAddressDisplay.tsx @@ -115,7 +115,7 @@ const BitcoinAddressDisplay: React.FC = React.memo( {address.utxoCount.toLocaleString()} unspent outputs diff --git a/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx b/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx index 51e9dae0..c8a9f861 100644 --- a/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx +++ b/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx @@ -92,6 +92,9 @@ const BitcoinBlockDisplay: React.FC = React.memo( {block.confirmations !== undefined && ( {block.confirmations.toLocaleString()} Confirmations + {settings.showHelperTooltips !== false && ( + + )} )} @@ -230,7 +233,7 @@ const BitcoinBlockDisplay: React.FC = React.memo( {block.weight.toLocaleString()} WU @@ -312,40 +315,36 @@ const BitcoinBlockDisplay: React.FC = React.memo(
    Merkle Root: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {block.merkleRoot}
    Version: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} 0x{block.version.toString(16)}
    Bits: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {block.bits}
    Nonce: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {block.nonce.toLocaleString()}
    @@ -353,10 +352,9 @@ const BitcoinBlockDisplay: React.FC = React.memo(
    Coinbase (hex): - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {block.coinbaseHex} diff --git a/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx b/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx index eee11c43..5d7bd5ed 100644 --- a/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx +++ b/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx @@ -1,7 +1,10 @@ import React, { useMemo } from "react"; +import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; +import { useSettings } from "../../../context/SettingsContext"; import CopyButton from "../../common/CopyButton"; import FieldLabel from "../../common/FieldLabel"; +import HelperTooltip from "../../common/HelperTooltip"; import { SATOSHIS_PER_BTC } from "../../../config/bitcoinConstants"; import { getNetworkById } from "../../../config/networks"; import type { BitcoinTransaction } from "../../../types"; @@ -46,6 +49,9 @@ interface BitcoinTransactionDisplayProps { const BitcoinTransactionDisplay: React.FC = React.memo( ({ transaction, networkId, btcPrice }) => { + const { t: tTooltips } = useTranslation("tooltips"); + const { settings } = useSettings(); + // Calculate totals const totalInput = calculateTotalInput(transaction); const totalOutput = calculateTotalOutput(transaction); @@ -129,6 +135,9 @@ const BitcoinTransactionDisplay: React.FC = Reac transaction.confirmations > 0 && ( {transaction.confirmations.toLocaleString()} Confirmations + {settings.showHelperTooltips !== false && ( + + )} ) )} @@ -156,7 +165,7 @@ const BitcoinTransactionDisplay: React.FC = Reac = Reac {feePerByte.toFixed(3)} sat/B
    @@ -285,7 +294,7 @@ const BitcoinTransactionDisplay: React.FC = Reac {feePerWU.toFixed(3)} sat/WU @@ -317,7 +326,7 @@ const BitcoinTransactionDisplay: React.FC = Reac {transaction.weight.toLocaleString()} WU @@ -369,7 +378,7 @@ const BitcoinTransactionDisplay: React.FC = Reac {transaction.version} @@ -377,7 +386,7 @@ const BitcoinTransactionDisplay: React.FC = Reac {transaction.locktime.toLocaleString()} @@ -389,7 +398,12 @@ const BitcoinTransactionDisplay: React.FC = Reac {/* Inputs Column */}
    - Inputs ({transaction.vin.length}) + + Inputs ({transaction.vin.length}) + {settings.showHelperTooltips !== false && ( + + )} + {totalInput > 0 && (
    {formatBTC(totalInput)} @@ -479,7 +493,12 @@ const BitcoinTransactionDisplay: React.FC = Reac {/* Outputs Column */}
    - Outputs ({transaction.vout.length}) + + Outputs ({transaction.vout.length}) + {settings.showHelperTooltips !== false && ( + + )} +
    {formatBTC(totalOutput)} {formatUSD(totalOutput, btcPrice) && ( diff --git a/src/components/pages/evm/address/shared/AccountMoreInfoCard.tsx b/src/components/pages/evm/address/shared/AccountMoreInfoCard.tsx index 3398aa5c..f041a67e 100644 --- a/src/components/pages/evm/address/shared/AccountMoreInfoCard.tsx +++ b/src/components/pages/evm/address/shared/AccountMoreInfoCard.tsx @@ -32,7 +32,7 @@ const AccountMoreInfoCard: React.FC = ({ @@ -60,7 +60,7 @@ const AccountMoreInfoCard: React.FC = ({ diff --git a/src/components/pages/evm/address/shared/AccountOverviewCard.tsx b/src/components/pages/evm/address/shared/AccountOverviewCard.tsx index e7e3c1e5..4b6fbb7b 100644 --- a/src/components/pages/evm/address/shared/AccountOverviewCard.tsx +++ b/src/components/pages/evm/address/shared/AccountOverviewCard.tsx @@ -138,7 +138,7 @@ const AccountOverviewCard: React.FC = ({ diff --git a/src/components/pages/evm/address/shared/AddressHeader.tsx b/src/components/pages/evm/address/shared/AddressHeader.tsx index 7abc45e4..9eb8248b 100644 --- a/src/components/pages/evm/address/shared/AddressHeader.tsx +++ b/src/components/pages/evm/address/shared/AddressHeader.tsx @@ -5,6 +5,8 @@ import type { AddressType, RPCMetadata } from "../../../../../types"; import { getAddressTypeIcon, getAddressTypeLabel } from "../../../../../utils/addressTypeDetection"; import { RPCIndicator } from "../../../../common/RPCIndicator"; import CopyButton from "../../../../common/CopyButton"; +import HelperTooltip from "../../../../common/HelperTooltip"; +import { useSettings } from "../../../../../context/SettingsContext"; interface AddressHeaderProps { addressHash: string; @@ -38,6 +40,8 @@ const AddressHeader: React.FC = ({ klerosTag, }) => { const { t } = useTranslation("address"); + const { settings } = useSettings(); + const { t: tTooltips } = useTranslation("tooltips"); const truncatedHash = truncateHash(addressHash, 4); return ( @@ -45,7 +49,12 @@ const AddressHeader: React.FC = ({
    {getAddressTypeIcon(addressType)} - {getAddressTypeLabel(addressType)} + + {getAddressTypeLabel(addressType)} + {settings.showHelperTooltips !== false && ( + + )} + {tokenSymbol && {tokenSymbol}} {klerosTag && ( = ({ } }} > - {t("contractBytecode")} + @@ -183,7 +188,11 @@ const ContractDetails: React.FC = ({ } }} > - {t("sourceCode")} + @@ -215,7 +224,11 @@ const ContractDetails: React.FC = ({ } }} > - {t("rawAbi")} + diff --git a/src/components/pages/evm/address/shared/ContractInfoCard.tsx b/src/components/pages/evm/address/shared/ContractInfoCard.tsx index 2a6072d1..ccf55b6c 100644 --- a/src/components/pages/evm/address/shared/ContractInfoCard.tsx +++ b/src/components/pages/evm/address/shared/ContractInfoCard.tsx @@ -194,7 +194,7 @@ const ContractInfoCard: React.FC = ({ {proxyInfo.type} @@ -207,7 +207,7 @@ const ContractInfoCard: React.FC = ({ diff --git a/src/components/pages/evm/address/shared/ContractInteraction.tsx b/src/components/pages/evm/address/shared/ContractInteraction.tsx index 606429c6..26f8bee6 100644 --- a/src/components/pages/evm/address/shared/ContractInteraction.tsx +++ b/src/components/pages/evm/address/shared/ContractInteraction.tsx @@ -260,7 +260,12 @@ const ContractInteraction: React.FC = ({ return (
    - {t("functions")} + + {t("functions")} + {settings.showHelperTooltips !== false && ( + + )} + {({ account, diff --git a/src/components/pages/evm/address/shared/ContractMoreInfoCard.tsx b/src/components/pages/evm/address/shared/ContractMoreInfoCard.tsx index fe996759..d81675bb 100644 --- a/src/components/pages/evm/address/shared/ContractMoreInfoCard.tsx +++ b/src/components/pages/evm/address/shared/ContractMoreInfoCard.tsx @@ -32,7 +32,7 @@ const ContractMoreInfoCard: React.FC = ({ @@ -60,7 +60,7 @@ const ContractMoreInfoCard: React.FC = ({ diff --git a/src/components/pages/evm/address/shared/NFTCollectionInfoCard.tsx b/src/components/pages/evm/address/shared/NFTCollectionInfoCard.tsx index e2b95ade..b8bc6b9a 100644 --- a/src/components/pages/evm/address/shared/NFTCollectionInfoCard.tsx +++ b/src/components/pages/evm/address/shared/NFTCollectionInfoCard.tsx @@ -67,7 +67,7 @@ const NFTCollectionInfoCard: React.FC = ({ @@ -94,7 +94,7 @@ const NFTCollectionInfoCard: React.FC = ({ diff --git a/src/components/pages/evm/address/shared/TransactionHistory.tsx b/src/components/pages/evm/address/shared/TransactionHistory.tsx index db621c0a..62023e4e 100644 --- a/src/components/pages/evm/address/shared/TransactionHistory.tsx +++ b/src/components/pages/evm/address/shared/TransactionHistory.tsx @@ -3,6 +3,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Link } from "react-router-dom"; import { toFunctionSelector } from "viem"; import { useTranslation } from "react-i18next"; +import { useSettings } from "../../../../../context/SettingsContext"; import { useDataService } from "../../../../../hooks/useDataService"; import type { ABI, @@ -10,6 +11,7 @@ import type { FunctionABI, Transaction, } from "../../../../../types"; +import HelperTooltip from "../../../../common/HelperTooltip"; // Transaction cache utilities const TX_CACHE_PREFIX = "tx_cache_"; @@ -127,6 +129,8 @@ const TransactionHistory: React.FC = ({ const loadMoreDropdownRef = useRef(null); const { t } = useTranslation("address"); + const { t: tTooltips } = useTranslation("tooltips"); + const { settings } = useSettings(); // Notify parent when transactions change useEffect(() => { @@ -522,13 +526,50 @@ const TransactionHistory: React.FC = ({ - - - {hasContractAbi && } - - - - + + + {hasContractAbi && ( + + )} + + + + diff --git a/src/components/pages/evm/block/BlockDisplay.tsx b/src/components/pages/evm/block/BlockDisplay.tsx index 3d489f15..9d37f770 100644 --- a/src/components/pages/evm/block/BlockDisplay.tsx +++ b/src/components/pages/evm/block/BlockDisplay.tsx @@ -161,7 +161,12 @@ const BlockDisplay: React.FC = React.memo( ({timestampFormatted}) - {t("finalized")} + + {t("finalized")} + {settings.showHelperTooltips !== false && ( + + )} + {metadata && selectedProvider !== undefined && onProviderSelect && ( = React.memo( {Number(block.difficulty).toLocaleString()} @@ -252,7 +257,7 @@ const BlockDisplay: React.FC = React.memo( {Number(block.totalDifficulty).toLocaleString()} @@ -276,7 +281,7 @@ const BlockDisplay: React.FC = React.memo( @@ -304,7 +309,7 @@ const BlockDisplay: React.FC = React.memo( {Number(block.gasUsed).toLocaleString()} @@ -317,7 +322,7 @@ const BlockDisplay: React.FC = React.memo( {Number(block.gasLimit).toLocaleString()} @@ -328,7 +333,7 @@ const BlockDisplay: React.FC = React.memo( {formatGwei(block.baseFeePerGas)} @@ -355,7 +360,7 @@ const BlockDisplay: React.FC = React.memo( {Number(block.excessBlobGas).toLocaleString()} @@ -381,7 +386,7 @@ const BlockDisplay: React.FC = React.memo( {Number(block.l1BlockNumber).toLocaleString()} @@ -391,7 +396,7 @@ const BlockDisplay: React.FC = React.memo( {block.sendCount} @@ -399,7 +404,7 @@ const BlockDisplay: React.FC = React.memo( {block.sendRoot} @@ -423,10 +428,9 @@ const BlockDisplay: React.FC = React.memo(
    Parent Hash: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {networkId && @@ -443,30 +447,27 @@ const BlockDisplay: React.FC = React.memo(
    State Root: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {block.stateRoot}
    Transactions Root: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {block.transactionsRoot}
    Receipts Root: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {block.receiptsRoot}
    @@ -474,10 +475,9 @@ const BlockDisplay: React.FC = React.memo(
    Withdrawals Root: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {block.withdrawalsRoot}
    @@ -485,10 +485,9 @@ const BlockDisplay: React.FC = React.memo(
    Logs Bloom: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )}
    {block.logsBloom} @@ -497,30 +496,27 @@ const BlockDisplay: React.FC = React.memo(
    Nonce: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {block.nonce}
    Mix Hash: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {block.mixHash}
    Sha3 Uncles: - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "advanced" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {block.sha3Uncles}
    @@ -594,10 +590,9 @@ const BlockDisplay: React.FC = React.memo(
    {t("validator")} - {settings.showHelperTooltips !== false && - settings.knowledgeLevel === "beginner" && ( - - )} + {settings.showHelperTooltips !== false && ( + + )} {Number(withdrawal.validatorIndex).toLocaleString()} diff --git a/src/components/pages/evm/network/DashboardStats.tsx b/src/components/pages/evm/network/DashboardStats.tsx index 43443ebe..80940f23 100644 --- a/src/components/pages/evm/network/DashboardStats.tsx +++ b/src/components/pages/evm/network/DashboardStats.tsx @@ -2,8 +2,10 @@ import type React from "react"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; import type { GasPrices } from "../../../../types"; +import { useSettings } from "../../../../context/SettingsContext"; import { formatPrice } from "../../../../services/PriceService"; import { formatGasPriceWithUnit } from "../../../../utils/formatUtils"; +import HelperTooltip from "../../../common/HelperTooltip"; interface DashboardStatsProps { price: number | null; @@ -35,13 +37,20 @@ const DashboardStats: React.FC = ({ networkId, }) => { const { t } = useTranslation("network"); + const { t: tTooltips } = useTranslation("tooltips"); + const { settings } = useSettings(); // Use gas tiers if available, otherwise fall back to single gas price const hasGasTiers = gasPrices !== null; return (
    -
    {t("currencyPrice", { currency })}
    +
    + {t("currencyPrice", { currency })} + {settings.showHelperTooltips !== false && ( + + )} +
    {loading ? ( = ({
    -
    {t("latestBlock")}
    +
    + {t("latestBlock")} + {settings.showHelperTooltips !== false && ( + + )} +
    {loading ? ( = React.memo(
    - {t("currentGasPrice")} + {formatGasPrice(networkStats.currentGasPrice)}
    - {t("currentBlockNumber")} + {formatBlockNumber(networkStats.currentBlockNumber)}
    - {t("syncStatus")} + = React.memo( {networkStats.clientVersion && (
    - {t("clientVersion")} + {networkStats.clientVersion}
    )} {protocolVersion && (
    - {t("protocolVersion")} + {protocolVersion}
    )} diff --git a/src/components/pages/evm/tokenDetails/ERC1155TokenDisplay.tsx b/src/components/pages/evm/tokenDetails/ERC1155TokenDisplay.tsx index a8bf293d..8ba4a669 100644 --- a/src/components/pages/evm/tokenDetails/ERC1155TokenDisplay.tsx +++ b/src/components/pages/evm/tokenDetails/ERC1155TokenDisplay.tsx @@ -243,7 +243,7 @@ const ERC1155TokenDetails: React.FC = () => { ERC-1155 diff --git a/src/components/pages/evm/tokenDetails/ERC721TokenDisplay.tsx b/src/components/pages/evm/tokenDetails/ERC721TokenDisplay.tsx index 6dc82c22..e99275c4 100644 --- a/src/components/pages/evm/tokenDetails/ERC721TokenDisplay.tsx +++ b/src/components/pages/evm/tokenDetails/ERC721TokenDisplay.tsx @@ -214,7 +214,7 @@ const ERC721TokenDisplay: React.FC = () => { ERC-721 diff --git a/src/components/pages/evm/tx/TransactionDisplay.tsx b/src/components/pages/evm/tx/TransactionDisplay.tsx index c730fc43..eec50fef 100644 --- a/src/components/pages/evm/tx/TransactionDisplay.tsx +++ b/src/components/pages/evm/tx/TransactionDisplay.tsx @@ -559,7 +559,7 @@ const TransactionDisplay: React.FC = React.memo( {transaction.to ? ( @@ -612,7 +612,7 @@ const TransactionDisplay: React.FC = React.memo( {getStatusText(transaction.receipt?.status)}
    @@ -622,7 +622,7 @@ const TransactionDisplay: React.FC = React.memo( {networkId ? ( @@ -732,7 +732,7 @@ const TransactionDisplay: React.FC = React.memo( {formatGwei(transaction.receipt.effectiveGasPrice)} @@ -745,7 +745,7 @@ const TransactionDisplay: React.FC = React.memo( {transaction.nonce}
    @@ -755,7 +755,7 @@ const TransactionDisplay: React.FC = React.memo( {transaction.transactionIndex}
    @@ -782,7 +782,7 @@ const TransactionDisplay: React.FC = React.memo( {Number(transaction.receipt.l1BlockNumber).toLocaleString()} @@ -794,7 +794,7 @@ const TransactionDisplay: React.FC = React.memo( {Number(transaction.receipt.gasUsedForL1).toLocaleString()} @@ -814,7 +814,7 @@ const TransactionDisplay: React.FC = React.memo( {formatValue(transaction.receipt.l1Fee)}
    @@ -824,7 +824,7 @@ const TransactionDisplay: React.FC = React.memo( {formatGwei(transaction.receipt.l1GasPrice)}
    @@ -836,7 +836,7 @@ const TransactionDisplay: React.FC = React.memo( {Number(transaction.receipt.l1GasUsed).toLocaleString()} @@ -848,7 +848,7 @@ const TransactionDisplay: React.FC = React.memo( {transaction.receipt.l1FeeScalar}
    @@ -919,7 +919,7 @@ const TransactionDisplay: React.FC = React.memo( {transaction.blobVersionedHashes.map((hash) => ( diff --git a/src/components/pages/evm/tx/TxAnalyser.tsx b/src/components/pages/evm/tx/TxAnalyser.tsx index d5503292..349104f1 100644 --- a/src/components/pages/evm/tx/TxAnalyser.tsx +++ b/src/components/pages/evm/tx/TxAnalyser.tsx @@ -205,7 +205,7 @@ const TxAnalyser: React.FC = ({ onClick={() => handleTabClick("inputData")} > {t("analyser.inputDataTab")} - {settings.showHelperTooltips !== false && settings.knowledgeLevel === "beginner" && ( + {settings.showHelperTooltips !== false && ( )} @@ -218,6 +218,9 @@ const TxAnalyser: React.FC = ({ onClick={() => handleTabClick("callTree")} > {t("analyser.callTree")} + {settings.showHelperTooltips !== false && ( + + )} )} diff --git a/src/components/pages/evm/tx/analyser/StateChangesTab.tsx b/src/components/pages/evm/tx/analyser/StateChangesTab.tsx index d6985c56..4369ba3e 100644 --- a/src/components/pages/evm/tx/analyser/StateChangesTab.tsx +++ b/src/components/pages/evm/tx/analyser/StateChangesTab.tsx @@ -7,6 +7,8 @@ import type { PrestateTrace, } from "../../../../../services/adapters/NetworkAdapter"; import type { ContractInfo } from "../../../../../utils/contractLookup"; +import HelperTooltip from "../../../../common/HelperTooltip"; +import { useSettings } from "../../../../../context/SettingsContext"; import LongString from "../../../../common/LongString"; function formatHexBalance(hex: string | undefined): string { @@ -42,6 +44,8 @@ const StateChangesTab: React.FC<{ contracts: Record; }> = ({ trace, networkId, networkCurrency, contracts }) => { const { t } = useTranslation("transaction"); + const { t: tTooltips } = useTranslation("tooltips"); + const { settings } = useSettings(); const [expandedSet, setExpandedSet] = useState>(new Set()); const allAddresses = Array.from(new Set([...Object.keys(trace.pre), ...Object.keys(trace.post)])); @@ -139,6 +143,9 @@ const StateChangesTab: React.FC<{
    {t("analyser.balanceChange")} ({networkCurrency}) + {settings.showHelperTooltips !== false && ( + + )} {formatHexBalance(pre.balance)} @@ -153,7 +160,12 @@ const StateChangesTab: React.FC<{ {nonceDiff && (
    - {t("analyser.nonceChange")} + + {t("analyser.nonceChange")} + {settings.showHelperTooltips !== false && ( + + )} + {pre.nonce ?? "—"} {post.nonce ?? "—"} @@ -165,7 +177,12 @@ const StateChangesTab: React.FC<{ {codeChanged && (
    - {t("analyser.codeDeployed")} + + {t("analyser.codeDeployed")} + {settings.showHelperTooltips !== false && ( + + )} + {post.code ? `${post.code.slice(0, 20)}…` : "—"} @@ -174,7 +191,12 @@ const StateChangesTab: React.FC<{ {storageKeys.map((slot) => (
    - {t("analyser.storageChange")} + + {t("analyser.storageChange")} + {settings.showHelperTooltips !== false && ( + + )} + diff --git a/src/locales/en/settings.json b/src/locales/en/settings.json index 02e02876..8ef767eb 100644 --- a/src/locales/en/settings.json +++ b/src/locales/en/settings.json @@ -158,7 +158,7 @@ }, "knowledgeLevel": { "label": "Knowledge Level", - "description": "Controls how many helper tooltips are shown. Beginner shows the most, Advanced shows the fewest.", + "description": "Controls how many helper tooltips are shown. Beginner shows all tooltips. Intermediate hides basic fields. Advanced shows only complex and chain-specific tooltips.", "beginner": "Beginner", "intermediate": "Intermediate", "advanced": "Advanced" diff --git a/src/locales/en/tooltips.json b/src/locales/en/tooltips.json index e99ee5e7..10be0d52 100644 --- a/src/locales/en/tooltips.json +++ b/src/locales/en/tooltips.json @@ -5,61 +5,76 @@ "status": "Whether the transaction executed successfully or reverted.", "confirmations": "Blocks mined after this transaction. More confirmations means higher finality.", "interactedWith": "The contract this transaction called, or the recipient address for simple transfers.", - "transactionFee": "Total fee paid to process this transaction (gas used × gas price).", + "transactionFee": "Total fee paid to process this transaction (gas used × gas price). Gas measures computational work on the network, and under EIP-1559 fees include a base fee (burned) plus a priority fee (tip).", "gasPrice": "Price per unit of gas, in Gwei. Higher gas prices incentivize faster inclusion.", "gasLimitUsage": "Gas limit is the maximum gas authorized. Gas used is the actual amount consumed.", - "nonce": "Sender's transaction counter. Ensures transactions are processed in order.", + "nonce": "Sender's transaction counter. Ensures transactions are processed in order and prevents replay attacks.", "position": "The index of this transaction within its block. Lower positions were processed first.", "type": "The transaction format (e.g. Legacy, EIP-1559, EIP-4844). Determines which fee fields apply.", "decodedInput": "The function call and parameters sent to the contract, decoded into human-readable form.", "maxFeePerBlobGas": "Maximum price per unit of blob gas the sender is willing to pay for data availability.", "blobGasPrice": "Actual price per unit of blob gas paid in this block.", - "blobGasUsed": "Amount of blob gas consumed by this transaction's data blobs.", - "blobCount": "Number of data blobs attached to this transaction for rollup data availability.", + "blobGasUsed": "Amount of blob gas consumed by this transaction's data blobs. Blobs are data containers introduced in EIP-4844 for rollup data availability, priced separately from execution gas.", + "blobCount": "Number of data containers attached to this transaction for rollup data availability.", "blobVersionedHashes": "Versioned hashes that uniquely identify each data blob committed by this transaction.", "contractCreated": "The address of the new contract deployed by this transaction.", "value": "Amount of native currency (e.g. ETH) transferred in this transaction.", "effectiveGasPrice": "The actual gas price paid after EIP-1559 fee calculation, which may differ from the requested price.", "l1BlockNumber": "The Ethereum L1 block that anchors this L2 transaction for security.", "gasUsedForL1": "Gas consumed for posting this transaction's data to Ethereum L1.", - "l1Fee": "Fee paid for data availability on Ethereum L1. Part of the total transaction cost on this L2.", + "l1Fee": "Fee paid for data availability on Ethereum L1. L2 networks rely on L1 to publish transaction data for security and verification.", "l1GasPrice": "The L1 gas price used to calculate the data availability fee component.", "l1GasUsed": "Estimated L1 gas required to post this transaction's calldata.", - "l1FeeScalar": "A multiplier applied to the L1 fee calculation by the L2 sequencer." + "l1FeeScalar": "A multiplier applied to the L1 fee calculation by the L2 sequencer.", + "txHashColumn": "The unique hash identifying this transaction.", + "blockColumn": "The block number this transaction was included in.", + "methodColumn": "The smart contract function called by this transaction.", + "fromColumn": "The address that sent this transaction.", + "toColumn": "The destination address of this transaction.", + "valueColumn": "The amount of native currency transferred.", + "statusColumn": "Whether the transaction succeeded or failed.", + "callTree": "Trace of all internal calls made during this transaction's execution.", + "gasProfiler": "Breakdown of gas consumption across each internal call.", + "stateChanges": "Blockchain state modifications (balances, nonces, storage) caused by this transaction.", + "balanceChange": "Change in native currency balance for this address caused by the transaction.", + "nonceChange": "Change in transaction count (nonce) for this address.", + "codeDeployed": "New contract bytecode deployed at this address by the transaction.", + "storageChange": "A storage slot in the contract's state that was modified by the transaction." }, "block": { "hash": "A unique fingerprint identifying this block, derived from its contents.", "transactions": "The number of transactions included and executed in this block.", "withdrawals": "Validator withdrawals processed in this block, returning staked ETH.", "feeRecipient": "The address that receives priority fees from transactions in this block.", - "difficulty": "Mining difficulty for this block. Always zero on proof-of-stake networks after the Merge.", + "difficulty": "Mining difficulty for this block. Zero on proof-of-stake networks after the Merge. On some L2 networks, this may be a non-zero constant.", "totalDifficulty": "Cumulative difficulty of the chain up to this block. Legacy field from proof-of-work.", "size": "The total size of the block data in bytes.", "extraData": "Arbitrary data set by the block producer. Often contains client or pool identifiers.", "gasUsed": "Total gas consumed by all transactions in this block.", "gasLimit": "Maximum gas allowed in this block, defining its capacity.", - "baseFeePerGas": "Minimum gas price for this block, set by the network based on demand (EIP-1559).", + "baseFeePerGas": "Minimum gas price for this block, set by the network based on demand (EIP-1559). This base fee is burned.", "burntFees": "Transaction fees permanently removed from circulation via EIP-1559.", "blobGasUsed": "Total blob gas consumed by blob transactions in this block.", "excessBlobGas": "Blob gas above the target, used to calculate the next block's blob base fee.", - "blobCount": "Number of data blobs included in this block for rollup data availability.", + "blobCount": "Number of data containers included in this block for rollup data availability.", "l1BlockNumber": "The Ethereum L1 block number associated with this Arbitrum block.", "sendCount": "Number of outgoing L2-to-L1 messages sent in this Arbitrum block.", "sendRoot": "Merkle root of all outgoing L2-to-L1 messages, used for cross-layer verification.", "parentHash": "Hash of the previous block in the chain, linking blocks together.", - "stateRoot": "Merkle root of the entire blockchain state after processing this block.", + "stateRoot": "Merkle root of the entire blockchain state (a cryptographic summary of all account data) after processing this block.", "transactionsRoot": "Merkle root of all transactions included in this block.", "receiptsRoot": "Merkle root of all transaction receipts from this block.", "withdrawalsRoot": "Merkle root of all validator withdrawals processed in this block.", - "logsBloom": "A bloom filter for efficiently searching event logs emitted in this block.", + "logsBloom": "A bloom filter (probabilistic data structure) for efficiently searching event logs emitted in this block.", "nonce": "A value used in proof-of-work mining. Always zero after the Merge.", "mixHash": "A hash used in the proof-of-work algorithm. Replaced by RANDAO value after the Merge.", "sha3Uncles": "Hash of the uncle blocks list. Always the empty list hash after the Merge.", - "validator": "The validator index that initiated this withdrawal from the beacon chain." + "validator": "The validator index that initiated this withdrawal from the beacon chain.", + "finalized": "This block has been finalized by the network's consensus mechanism and cannot be reverted." }, "address": { "verification": "A verified contract has its source code publicly confirmed to match the deployed bytecode.", - "proxyType": "This contract uses an upgradeable proxy pattern. The logic lives in a separate implementation contract.", + "proxyType": "This contract uses an upgradeable proxy pattern, where execution is delegated to a separate implementation contract, allowing upgrades without changing the address.", "readContract": "Query contract data without spending gas or connecting a wallet. Read-only calls.", "writeContract": "Send a transaction that changes contract state. Requires a connected wallet and gas.", "balance": "Native currency balance held by this address.", @@ -67,8 +82,13 @@ "nonce": "Number of transactions sent from this address. Used for transaction ordering.", "eip7702Delegate": "This account delegates its code execution to another address via EIP-7702.", "implementationAddress": "The contract that contains the actual logic for this proxy.", - "ensName": "Ethereum Name Service name associated with this address.", - "ensApp": "Application or resolver linked to this ENS name." + "ensName": "Ethereum Name Service (maps human-readable names to addresses) name associated with this address.", + "ensApp": "Application or resolver linked to this ENS name.", + "accountType": "The type of this address. EOA (Externally Owned Account) is a regular wallet controlled by a private key. Contract is code deployed on-chain.", + "contractBytecode": "The compiled EVM bytecode deployed at this address.", + "sourceCode": "The original Solidity/Vyper source code, verified to match the deployed bytecode.", + "rawAbi": "The Application Binary Interface (ABI) defines how to interact with this contract's functions.", + "functions": "Available contract functions that can be called to read data or modify state." }, "token": { "tokenStandard": "The token interface standard (e.g. ERC-20, ERC-721, ERC-1155) that defines how this token behaves.", @@ -84,7 +104,7 @@ "witnessHash": "Transaction hash including witness (SegWit) data. Differs from TXID for SegWit transactions.", "block": "The block that includes this transaction.", "status": "Whether this transaction has been confirmed in a block or is still waiting in the mempool.", - "inputs": "The number of previous outputs being spent. Each input references a UTXO.", + "inputs": "The number of previous outputs being spent. Each input references a UTXO. Bitcoin uses a UTXO model where transactions consume and create discrete outputs.", "outputs": "The number of new outputs created. Each output locks BTC to an address.", "fee": "The difference between total inputs and total outputs, paid to the miner.", "feePerByte": "Fee rate in satoshis per byte of raw transaction data.", @@ -111,7 +131,7 @@ "previousBlock": "Hash of the preceding block, linking this block to the chain.", "nextBlock": "Hash of the following block, if one exists.", "coinbaseMessage": "Arbitrary text embedded in the coinbase transaction by the miner.", - "merkleRoot": "Root hash of the Merkle tree of all transactions in this block.", + "merkleRoot": "Root hash of the Merkle tree (a structure that allows efficient verification) of all transactions in this block.", "blockVersion": "Block format version. Encodes which consensus rules and soft forks are signaled.", "bits": "Compact encoding of the target threshold for a valid block hash.", "blockNonce": "A value miners iterate to find a block hash below the target.", @@ -120,7 +140,20 @@ "balance": "Total BTC held by this address across all unspent outputs.", "totalReceived": "Cumulative BTC received by this address across all transactions.", "utxos": "Unspent Transaction Outputs. Individual coins available to be spent by this address.", - "txCount": "Total number of transactions involving this address." + "txCount": "Total number of transactions involving this address.", + "blockConfirmations": "Blocks mined after this block. More confirmations means the block is more deeply embedded in the chain.", + "confirmations": "Blocks mined after the block containing this transaction. More confirmations means higher finality.", + "inputsColumn": "Previous transaction outputs being spent. Each input references a UTXO (Unspent Transaction Output).", + "outputsColumn": "New outputs created by this transaction. Each output locks BTC to a recipient address." + }, + "network": { + "gasPrice": "Current cost per unit of gas on this network.", + "blockNumber": "The most recently mined block number on this network.", + "syncStatus": "Whether the connected node has fully synced with the network.", + "clientVersion": "The software client and version running on the connected node.", + "protocolVersion": "The Ethereum protocol version supported by the connected node.", + "currencyPrice": "Current market price of this network's native currency.", + "latestBlock": "The most recently produced block on this network." }, "settings": { "knowledgeLevel": "Controls how much explanatory help is shown throughout the explorer." diff --git a/src/locales/es/settings.json b/src/locales/es/settings.json index b4cf270a..0e2936e9 100644 --- a/src/locales/es/settings.json +++ b/src/locales/es/settings.json @@ -158,7 +158,7 @@ }, "knowledgeLevel": { "label": "Nivel de Conocimiento", - "description": "Controla cuántos tooltips de ayuda se muestran. Principiante muestra más, Avanzado muestra menos.", + "description": "Controla cuántos tooltips de ayuda se muestran. Principiante muestra todos. Intermedio oculta campos básicos. Avanzado muestra solo tooltips complejos y específicos de la cadena.", "beginner": "Principiante", "intermediate": "Intermedio", "advanced": "Avanzado" diff --git a/src/locales/es/tooltips.json b/src/locales/es/tooltips.json index 079e9877..68feb29c 100644 --- a/src/locales/es/tooltips.json +++ b/src/locales/es/tooltips.json @@ -5,61 +5,76 @@ "status": "Si la transacción se ejecutó correctamente o fue revertida.", "confirmations": "Bloques minados después de esta transacción. Más confirmaciones significa mayor finalidad.", "interactedWith": "El contrato con el que interactuó esta transacción, o la dirección del destinatario en transferencias simples.", - "transactionFee": "Tarifa total pagada para procesar esta transacción (gas usado × precio del gas).", + "transactionFee": "Tarifa total pagada para procesar esta transacción (gas usado × precio del gas). El gas mide el trabajo computacional en la red, y bajo EIP-1559 las tarifas incluyen una tarifa base (quemada) más una tarifa de prioridad (propina).", "gasPrice": "Precio por unidad de gas, en Gwei. Precios más altos incentivan una inclusión más rápida.", "gasLimitUsage": "El límite de gas es el máximo autorizado. El gas usado es la cantidad real consumida.", - "nonce": "Contador de transacciones del remitente. Asegura que las transacciones se procesen en orden.", + "nonce": "Contador de transacciones del remitente. Asegura que las transacciones se procesen en orden y previene ataques de repetición.", "position": "El índice de esta transacción dentro de su bloque. Posiciones más bajas se procesaron primero.", "type": "El formato de la transacción (ej. Legacy, EIP-1559, EIP-4844). Determina qué campos de tarifa aplican.", "decodedInput": "La llamada a función y parámetros enviados al contrato, decodificados en formato legible.", "maxFeePerBlobGas": "Precio máximo por unidad de blob gas que el remitente está dispuesto a pagar por disponibilidad de datos.", "blobGasPrice": "Precio real por unidad de blob gas pagado en este bloque.", - "blobGasUsed": "Cantidad de blob gas consumido por los blobs de datos de esta transacción.", - "blobCount": "Cantidad de blobs de datos adjuntos a esta transacción para disponibilidad de datos de rollup.", + "blobGasUsed": "Cantidad de blob gas consumido por los blobs de datos de esta transacción. Los blobs son contenedores de datos introducidos en EIP-4844 para disponibilidad de datos de rollup, con precio separado del gas de ejecución.", + "blobCount": "Cantidad de contenedores de datos adjuntos a esta transacción para disponibilidad de datos de rollup.", "blobVersionedHashes": "Hashes versionados que identifican de forma única cada blob de datos comprometido por esta transacción.", "contractCreated": "La dirección del nuevo contrato desplegado por esta transacción.", "value": "Cantidad de moneda nativa (ej. ETH) transferida en esta transacción.", "effectiveGasPrice": "El precio de gas real pagado después del cálculo de tarifa EIP-1559, que puede diferir del precio solicitado.", "l1BlockNumber": "El bloque de Ethereum L1 que ancla esta transacción L2 para seguridad.", "gasUsedForL1": "Gas consumido para publicar los datos de esta transacción en Ethereum L1.", - "l1Fee": "Tarifa pagada por disponibilidad de datos en Ethereum L1. Parte del costo total de la transacción en esta L2.", + "l1Fee": "Tarifa pagada por disponibilidad de datos en Ethereum L1. Las redes L2 dependen de L1 para publicar datos de transacciones por seguridad y verificación.", "l1GasPrice": "El precio de gas L1 usado para calcular el componente de tarifa de disponibilidad de datos.", "l1GasUsed": "Gas L1 estimado requerido para publicar los calldata de esta transacción.", - "l1FeeScalar": "Un multiplicador aplicado al cálculo de tarifa L1 por el secuenciador L2." + "l1FeeScalar": "Un multiplicador aplicado al cálculo de tarifa L1 por el secuenciador L2.", + "txHashColumn": "El hash único que identifica esta transacción.", + "blockColumn": "El número de bloque en el que se incluyó esta transacción.", + "methodColumn": "La función del contrato inteligente llamada por esta transacción.", + "fromColumn": "La dirección que envió esta transacción.", + "toColumn": "La dirección de destino de esta transacción.", + "valueColumn": "La cantidad de moneda nativa transferida.", + "statusColumn": "Si la transacción tuvo éxito o falló.", + "callTree": "Rastreo de todas las llamadas internas realizadas durante la ejecución de esta transacción.", + "gasProfiler": "Desglose del consumo de gas en cada llamada interna.", + "stateChanges": "Modificaciones del estado de la blockchain (saldos, nonces, almacenamiento) causadas por esta transacción.", + "balanceChange": "Cambio en el saldo de moneda nativa de esta dirección causado por la transacción.", + "nonceChange": "Cambio en el contador de transacciones (nonce) de esta dirección.", + "codeDeployed": "Nuevo bytecode de contrato desplegado en esta dirección por la transacción.", + "storageChange": "Un slot de almacenamiento en el estado del contrato que fue modificado por la transacción." }, "block": { "hash": "Una huella digital única que identifica este bloque, derivada de su contenido.", "transactions": "La cantidad de transacciones incluidas y ejecutadas en este bloque.", "withdrawals": "Retiros de validadores procesados en este bloque, devolviendo ETH stakeado.", "feeRecipient": "La dirección que recibe las tarifas prioritarias de las transacciones en este bloque.", - "difficulty": "Dificultad de minado para este bloque. Siempre cero en redes proof-of-stake después del Merge.", + "difficulty": "Dificultad de minado para este bloque. Cero en redes proof-of-stake después del Merge. En algunas redes L2, puede ser una constante distinta de cero.", "totalDifficulty": "Dificultad acumulada de la cadena hasta este bloque. Campo heredado de proof-of-work.", "size": "El tamaño total de los datos del bloque en bytes.", "extraData": "Datos arbitrarios establecidos por el productor del bloque. A menudo contiene identificadores de cliente o pool.", "gasUsed": "Gas total consumido por todas las transacciones en este bloque.", "gasLimit": "Gas máximo permitido en este bloque, definiendo su capacidad.", - "baseFeePerGas": "Precio mínimo de gas para este bloque, establecido por la red según la demanda (EIP-1559).", + "baseFeePerGas": "Precio mínimo de gas para este bloque, establecido por la red según la demanda (EIP-1559). Esta tarifa base se quema.", "burntFees": "Tarifas de transacción eliminadas permanentemente de la circulación mediante EIP-1559.", "blobGasUsed": "Blob gas total consumido por transacciones blob en este bloque.", "excessBlobGas": "Blob gas por encima del objetivo, usado para calcular la tarifa base blob del siguiente bloque.", - "blobCount": "Cantidad de blobs de datos incluidos en este bloque para disponibilidad de datos de rollup.", + "blobCount": "Cantidad de contenedores de datos incluidos en este bloque para disponibilidad de datos de rollup.", "l1BlockNumber": "El número de bloque de Ethereum L1 asociado con este bloque de Arbitrum.", "sendCount": "Cantidad de mensajes salientes L2-a-L1 enviados en este bloque de Arbitrum.", "sendRoot": "Raíz de Merkle de todos los mensajes salientes L2-a-L1, usada para verificación entre capas.", "parentHash": "Hash del bloque anterior en la cadena, enlazando los bloques entre sí.", - "stateRoot": "Raíz de Merkle del estado completo de la blockchain después de procesar este bloque.", + "stateRoot": "Raíz de Merkle del estado completo de la blockchain (un resumen criptográfico de todos los datos de cuentas) después de procesar este bloque.", "transactionsRoot": "Raíz de Merkle de todas las transacciones incluidas en este bloque.", "receiptsRoot": "Raíz de Merkle de todos los recibos de transacciones de este bloque.", "withdrawalsRoot": "Raíz de Merkle de todos los retiros de validadores procesados en este bloque.", - "logsBloom": "Un filtro bloom para buscar eficientemente logs de eventos emitidos en este bloque.", + "logsBloom": "Un filtro bloom (estructura de datos probabilística) para buscar eficientemente logs de eventos emitidos en este bloque.", "nonce": "Un valor usado en minería proof-of-work. Siempre cero después del Merge.", "mixHash": "Un hash usado en el algoritmo proof-of-work. Reemplazado por el valor RANDAO después del Merge.", "sha3Uncles": "Hash de la lista de bloques uncle. Siempre el hash de lista vacía después del Merge.", - "validator": "El índice del validador que inició este retiro desde la beacon chain." + "validator": "El índice del validador que inició este retiro desde la beacon chain.", + "finalized": "Este bloque ha sido finalizado por el mecanismo de consenso de la red y no puede ser revertido." }, "address": { "verification": "Un contrato verificado tiene su código fuente confirmado públicamente como coincidente con el bytecode desplegado.", - "proxyType": "Este contrato usa un patrón de proxy actualizable. La lógica está en un contrato de implementación separado.", + "proxyType": "Este contrato usa un patrón de proxy actualizable, donde la ejecución se delega a un contrato de implementación separado, permitiendo actualizaciones sin cambiar la dirección.", "readContract": "Consultar datos del contrato sin gastar gas ni conectar una wallet. Llamadas de solo lectura.", "writeContract": "Enviar una transacción que cambia el estado del contrato. Requiere una wallet conectada y gas.", "balance": "Saldo de moneda nativa que posee esta dirección.", @@ -67,8 +82,13 @@ "nonce": "Cantidad de transacciones enviadas desde esta dirección. Usado para ordenar transacciones.", "eip7702Delegate": "Esta cuenta delega la ejecución de su código a otra dirección vía EIP-7702.", "implementationAddress": "El contrato que contiene la lógica real para este proxy.", - "ensName": "Nombre del Ethereum Name Service asociado a esta dirección.", - "ensApp": "Aplicación o resolver vinculado a este nombre ENS." + "ensName": "Nombre del Ethereum Name Service (mapea nombres legibles a direcciones) asociado a esta dirección.", + "ensApp": "Aplicación o resolver vinculado a este nombre ENS.", + "accountType": "El tipo de esta dirección. EOA (Cuenta de Propiedad Externa) es una wallet regular controlada por una clave privada. Contrato es código desplegado en la cadena.", + "contractBytecode": "El bytecode EVM compilado desplegado en esta dirección.", + "sourceCode": "El código fuente original en Solidity/Vyper, verificado para coincidir con el bytecode desplegado.", + "rawAbi": "La Interfaz Binaria de Aplicación (ABI) define cómo interactuar con las funciones de este contrato.", + "functions": "Funciones de contrato disponibles que pueden ser llamadas para leer datos o modificar el estado." }, "token": { "tokenStandard": "El estándar de interfaz del token (ej. ERC-20, ERC-721, ERC-1155) que define cómo se comporta.", @@ -84,7 +104,7 @@ "witnessHash": "Hash de transacción incluyendo datos witness (SegWit). Difiere del TXID para transacciones SegWit.", "block": "El bloque que incluye esta transacción.", "status": "Si esta transacción fue confirmada en un bloque o sigue esperando en el mempool.", - "inputs": "La cantidad de salidas previas que se gastan. Cada entrada referencia un UTXO.", + "inputs": "La cantidad de salidas previas que se gastan. Cada entrada referencia un UTXO. Bitcoin usa un modelo UTXO donde las transacciones consumen y crean salidas discretas.", "outputs": "La cantidad de nuevas salidas creadas. Cada salida bloquea BTC a una dirección.", "fee": "La diferencia entre entradas y salidas totales, pagada al minero.", "feePerByte": "Tasa de tarifa en satoshis por byte de datos crudos de transacción.", @@ -111,7 +131,7 @@ "previousBlock": "Hash del bloque precedente, enlazando este bloque a la cadena.", "nextBlock": "Hash del bloque siguiente, si existe.", "coinbaseMessage": "Texto arbitrario incrustado en la transacción coinbase por el minero.", - "merkleRoot": "Hash raíz del árbol de Merkle de todas las transacciones en este bloque.", + "merkleRoot": "Hash raíz del árbol de Merkle (una estructura que permite verificación eficiente) de todas las transacciones en este bloque.", "blockVersion": "Versión del formato de bloque. Codifica qué reglas de consenso y soft forks se señalizan.", "bits": "Codificación compacta del umbral objetivo para un hash de bloque válido.", "blockNonce": "Un valor que los mineros iteran para encontrar un hash de bloque por debajo del objetivo.", @@ -120,7 +140,20 @@ "balance": "BTC total que posee esta dirección en todas las salidas sin gastar.", "totalReceived": "BTC acumulados recibidos por esta dirección en todas las transacciones.", "utxos": "Salidas de Transacción No Gastadas. Monedas individuales disponibles para gastar por esta dirección.", - "txCount": "Cantidad total de transacciones que involucran esta dirección." + "txCount": "Cantidad total de transacciones que involucran esta dirección.", + "blockConfirmations": "Bloques minados después de este bloque. Más confirmaciones significa que el bloque está más profundamente integrado en la cadena.", + "confirmations": "Bloques minados después del bloque que contiene esta transacción. Más confirmaciones significa mayor finalidad.", + "inputsColumn": "Salidas de transacciones previas siendo gastadas. Cada entrada referencia un UTXO (Salida de Transacción No Gastada).", + "outputsColumn": "Nuevas salidas creadas por esta transacción. Cada salida bloquea BTC a una dirección receptora." + }, + "network": { + "gasPrice": "Costo actual por unidad de gas en esta red.", + "blockNumber": "El número de bloque más reciente minado en esta red.", + "syncStatus": "Si el nodo conectado se ha sincronizado completamente con la red.", + "clientVersion": "El software cliente y versión que ejecuta el nodo conectado.", + "protocolVersion": "La versión del protocolo Ethereum soportada por el nodo conectado.", + "currencyPrice": "Precio de mercado actual de la moneda nativa de esta red.", + "latestBlock": "El bloque más reciente producido en esta red." }, "settings": { "knowledgeLevel": "Controla cuánta ayuda explicativa se muestra en el explorador." diff --git a/src/locales/ja/settings.json b/src/locales/ja/settings.json index a50abd00..788ac69a 100644 --- a/src/locales/ja/settings.json +++ b/src/locales/ja/settings.json @@ -158,7 +158,7 @@ }, "knowledgeLevel": { "label": "知識レベル", - "description": "ヘルパーツールチップの表示数を制御します。初心者は最も多く、上級者は最も少なく表示されます。", + "description": "ヘルパーツールチップの表示数を制御します。初心者はすべて表示。中級者は基本フィールドを非表示。上級者は複雑なチェーン固有のツールチップのみ表示。", "beginner": "初心者", "intermediate": "中級者", "advanced": "上級者" diff --git a/src/locales/ja/tooltips.json b/src/locales/ja/tooltips.json index 65264a25..47efb91f 100644 --- a/src/locales/ja/tooltips.json +++ b/src/locales/ja/tooltips.json @@ -5,61 +5,76 @@ "status": "トランザクションが正常に実行されたか、リバートされたか。", "confirmations": "このトランザクション後にマイニングされたブロック数。確認数が多いほどファイナリティが高い。", "interactedWith": "このトランザクションが呼び出したコントラクト、または単純な送金の受取アドレス。", - "transactionFee": "このトランザクションの処理に支払われた合計手数料(使用ガス × ガス価格)。", + "transactionFee": "このトランザクションの処理に支払われた合計手数料(使用ガス × ガス価格)。ガスはネットワーク上の計算作業を測定し、EIP-1559ではベース手数料(バーン)とプライオリティ手数料(チップ)が含まれます。", "gasPrice": "ガス1単位あたりの価格(Gwei単位)。高いガス価格はより早い取り込みを促進します。", "gasLimitUsage": "ガスリミットは承認された最大ガス量。使用ガスは実際に消費された量。", - "nonce": "送信者のトランザクションカウンター。トランザクションが順番に処理されることを保証します。", + "nonce": "送信者のトランザクションカウンター。トランザクションが順番に処理されることを保証し、リプレイ攻撃を防止します。", "position": "ブロック内のこのトランザクションのインデックス。低い位置が先に処理されます。", "type": "トランザクション形式(例:Legacy、EIP-1559、EIP-4844)。適用される手数料フィールドを決定します。", "decodedInput": "コントラクトに送信された関数呼び出しとパラメータを人間が読める形式にデコードしたもの。", "maxFeePerBlobGas": "送信者がデータ可用性のために支払うBlobガス1単位あたりの最高価格。", "blobGasPrice": "このブロックで支払われたBlobガス1単位あたりの実際の価格。", - "blobGasUsed": "このトランザクションのデータBlobが消費したBlobガスの量。", - "blobCount": "ロールアップデータ可用性のためにこのトランザクションに添付されたデータBlobの数。", + "blobGasUsed": "このトランザクションのデータBlobが消費したBlobガスの量。Blobはロールアップデータ可用性のためにEIP-4844で導入されたデータコンテナで、実行ガスとは別に価格設定されます。", + "blobCount": "ロールアップデータ可用性のためにこのトランザクションに添付されたデータコンテナの数。", "blobVersionedHashes": "このトランザクションがコミットした各データBlobを一意に識別するバージョン付きハッシュ。", "contractCreated": "このトランザクションによってデプロイされた新しいコントラクトのアドレス。", "value": "このトランザクションで送金されたネイティブ通貨(例:ETH)の金額。", "effectiveGasPrice": "EIP-1559の手数料計算後に実際に支払われたガス価格。リクエストした価格と異なる場合があります。", "l1BlockNumber": "このL2トランザクションのセキュリティを担保するEthereum L1ブロック。", "gasUsedForL1": "このトランザクションのデータをEthereum L1に投稿するために消費されたガス。", - "l1Fee": "Ethereum L1でのデータ可用性に支払われた手数料。このL2の合計トランザクションコストの一部。", + "l1Fee": "Ethereum L1でのデータ可用性に支払われた手数料。L2ネットワークはセキュリティと検証のためにL1にトランザクションデータを公開することに依存しています。", "l1GasPrice": "データ可用性手数料の計算に使用されたL1ガス価格。", "l1GasUsed": "このトランザクションのcalldataを投稿するために必要な推定L1ガス。", - "l1FeeScalar": "L2シーケンサーがL1手数料計算に適用する乗数。" + "l1FeeScalar": "L2シーケンサーがL1手数料計算に適用する乗数。", + "txHashColumn": "このトランザクションを識別する一意のハッシュ。", + "blockColumn": "このトランザクションが含まれたブロック番号。", + "methodColumn": "このトランザクションが呼び出したスマートコントラクト関数。", + "fromColumn": "このトランザクションを送信したアドレス。", + "toColumn": "このトランザクションの宛先アドレス。", + "valueColumn": "転送されたネイティブ通貨の量。", + "statusColumn": "トランザクションが成功したか失敗したか。", + "callTree": "このトランザクション実行中に行われたすべての内部呼び出しのトレース。", + "gasProfiler": "各内部呼び出しにおけるガス消費の内訳。", + "stateChanges": "このトランザクションによって引き起こされたブロックチェーン状態の変更(残高、ノンス、ストレージ)。", + "balanceChange": "トランザクションによるこのアドレスのネイティブ通貨残高の変化。", + "nonceChange": "このアドレスのトランザクションカウント(ノンス)の変化。", + "codeDeployed": "トランザクションによってこのアドレスにデプロイされた新しいコントラクトバイトコード。", + "storageChange": "トランザクションによって変更されたコントラクト状態のストレージスロット。" }, "block": { "hash": "このブロックを識別する一意のフィンガープリント。内容から導出されます。", "transactions": "このブロックに含まれ実行されたトランザクションの数。", "withdrawals": "このブロックで処理されたバリデーターの引き出し。ステークされたETHを返却します。", "feeRecipient": "このブロック内のトランザクションから優先手数料を受け取るアドレス。", - "difficulty": "このブロックのマイニング難易度。マージ後のProof of Stakeネットワークでは常にゼロ。", + "difficulty": "このブロックのマイニング難易度。マージ後のProof of Stakeネットワークではゼロ。一部のL2ネットワークでは、ゼロでない定数の場合があります。", "totalDifficulty": "このブロックまでのチェーンの累積難易度。Proof of Workのレガシーフィールド。", "size": "ブロックデータの合計サイズ(バイト)。", "extraData": "ブロック生成者が設定した任意のデータ。クライアントやプールの識別子が含まれることが多い。", "gasUsed": "このブロック内の全トランザクションで消費された合計ガス。", "gasLimit": "このブロックで許可される最大ガス量。ブロックの容量を定義します。", - "baseFeePerGas": "このブロックの最低ガス価格。ネットワークの需要に基づいて設定されます(EIP-1559)。", + "baseFeePerGas": "このブロックの最低ガス価格。ネットワークの需要に基づいて設定されます(EIP-1559)。このベース手数料はバーンされます。", "burntFees": "EIP-1559により流通から永久に除去されたトランザクション手数料。", "blobGasUsed": "このブロック内のBlobトランザクションが消費した合計Blobガス。", "excessBlobGas": "目標を超えたBlobガス。次のブロックのBlob基本手数料の計算に使用されます。", - "blobCount": "ロールアップデータ可用性のためにこのブロックに含まれるデータBlobの数。", + "blobCount": "ロールアップデータ可用性のためにこのブロックに含まれるデータコンテナの数。", "l1BlockNumber": "このArbitrumブロックに関連するEthereum L1ブロック番号。", "sendCount": "このArbitrumブロックで送信されたL2からL1への送信メッセージの数。", "sendRoot": "すべてのL2からL1への送信メッセージのMerkleルート。クロスレイヤー検証に使用されます。", "parentHash": "チェーン内の前のブロックのハッシュ。ブロック同士をリンクします。", - "stateRoot": "このブロックの処理後のブロックチェーン全体の状態のMerkleルート。", + "stateRoot": "このブロックの処理後のブロックチェーン全体の状態(すべてのアカウントデータの暗号化サマリー)のMerkleルート。", "transactionsRoot": "このブロックに含まれるすべてのトランザクションのMerkleルート。", "receiptsRoot": "このブロックのすべてのトランザクションレシートのMerkleルート。", "withdrawalsRoot": "このブロックで処理されたすべてのバリデーター引き出しのMerkleルート。", - "logsBloom": "このブロックで発行されたイベントログを効率的に検索するためのブルームフィルター。", + "logsBloom": "このブロックで発行されたイベントログを効率的に検索するためのブルームフィルター(確率的データ構造)。", "nonce": "Proof of Workマイニングで使用される値。マージ後は常にゼロ。", "mixHash": "Proof of Workアルゴリズムで使用されるハッシュ。マージ後はRANDAO値に置き換えられました。", "sha3Uncles": "アンクルブロックリストのハッシュ。マージ後は常に空リストのハッシュ。", - "validator": "ビーコンチェーンからこの引き出しを開始したバリデーターインデックス。" + "validator": "ビーコンチェーンからこの引き出しを開始したバリデーターインデックス。", + "finalized": "このブロックはネットワークのコンセンサスメカニズムによってファイナライズされ、取り消すことはできません。" }, "address": { "verification": "検証済みコントラクトは、ソースコードがデプロイされたバイトコードと一致することが公開確認されています。", - "proxyType": "このコントラクトはアップグレード可能なプロキシパターンを使用しています。ロジックは別の実装コントラクトにあります。", + "proxyType": "このコントラクトはアップグレード可能なプロキシパターンを使用しており、実行は別の実装コントラクトに委任され、アドレスを変更せずにアップグレードが可能です。", "readContract": "ガスを消費せず、ウォレットを接続せずにコントラクトデータを照会。読み取り専用の呼び出し。", "writeContract": "コントラクトの状態を変更するトランザクションを送信。接続されたウォレットとガスが必要です。", "balance": "このアドレスが保有するネイティブ通貨の残高。", @@ -67,8 +82,13 @@ "nonce": "このアドレスから送信されたトランザクション数。トランザクションの順序付けに使用されます。", "eip7702Delegate": "このアカウントはEIP-7702を介してコード実行を別のアドレスに委任しています。", "implementationAddress": "このプロキシの実際のロジックを含むコントラクト。", - "ensName": "このアドレスに関連付けられたEthereum Name Serviceの名前。", - "ensApp": "このENS名前にリンクされたアプリケーションまたはリゾルバー。" + "ensName": "このアドレスに関連付けられたEthereum Name Service(人間が読める名前をアドレスにマッピング)の名前。", + "ensApp": "このENS名前にリンクされたアプリケーションまたはリゾルバー。", + "accountType": "このアドレスの種類。EOA(外部所有アカウント)は秘密鍵で制御される通常のウォレット。コントラクトはチェーン上にデプロイされたコードです。", + "contractBytecode": "このアドレスにデプロイされたコンパイル済みEVMバイトコード。", + "sourceCode": "デプロイされたバイトコードと一致することが検証された、元のSolidity/Vyperソースコード。", + "rawAbi": "アプリケーションバイナリインターフェース(ABI)は、このコントラクトの関数との対話方法を定義します。", + "functions": "データの読み取りまたは状態の変更のために呼び出し可能なコントラクト関数。" }, "token": { "tokenStandard": "トークンのインターフェース標準(ERC-20、ERC-721、ERC-1155など)。トークンの動作を定義します。", @@ -84,7 +104,7 @@ "witnessHash": "ウィットネス(SegWit)データを含むトランザクションハッシュ。SegWitトランザクションではTXIDと異なります。", "block": "このトランザクションを含むブロック。", "status": "このトランザクションがブロックで確認されたか、まだメモリプールで待機中か。", - "inputs": "使用される以前の出力の数。各入力はUTXOを参照します。", + "inputs": "使用される以前の出力の数。各入力はUTXOを参照します。BitcoinはUTXOモデルを使用し、トランザクションは個別の出力を消費・作成します。", "outputs": "作成される新しい出力の数。各出力はBTCをアドレスにロックします。", "fee": "入力合計と出力合計の差額。マイナーに支払われます。", "feePerByte": "生のトランザクションデータ1バイトあたりの手数料率(satoshi)。", @@ -111,7 +131,7 @@ "previousBlock": "前のブロックのハッシュ。このブロックをチェーンにリンクします。", "nextBlock": "次のブロックのハッシュ(存在する場合)。", "coinbaseMessage": "マイナーがコインベーストランザクションに埋め込んだ任意のテキスト。", - "merkleRoot": "このブロック内の全トランザクションのMerkleツリーのルートハッシュ。", + "merkleRoot": "このブロック内の全トランザクションのMerkleツリー(効率的な検証を可能にする構造)のルートハッシュ。", "blockVersion": "ブロックフォーマットのバージョン。どのコンセンサスルールとソフトフォークがシグナルされるかをエンコード。", "bits": "有効なブロックハッシュのターゲット閾値のコンパクトエンコーディング。", "blockNonce": "マイナーがターゲット以下のブロックハッシュを見つけるために反復する値。", @@ -120,7 +140,20 @@ "balance": "このアドレスが全未使用出力にわたって保有するBTC合計。", "totalReceived": "このアドレスが全トランザクションにわたって受け取った累計BTC。", "utxos": "未使用トランザクション出力。このアドレスが使用可能な個別のコイン。", - "txCount": "このアドレスに関連するトランザクションの総数。" + "txCount": "このアドレスに関連するトランザクションの総数。", + "blockConfirmations": "このブロック後にマイニングされたブロック数。確認数が多いほどブロックがチェーンに深く埋め込まれています。", + "confirmations": "このトランザクションを含むブロック後にマイニングされたブロック数。確認数が多いほどファイナリティが高い。", + "inputsColumn": "使用される以前のトランザクション出力。各入力はUTXO(未使用トランザクション出力)を参照します。", + "outputsColumn": "このトランザクションによって作成された新しい出力。各出力は受取アドレスにBTCをロックします。" + }, + "network": { + "gasPrice": "このネットワークのガス1単位あたりの現在のコスト。", + "blockNumber": "このネットワークで最も最近マイニングされたブロック番号。", + "syncStatus": "接続されたノードがネットワークと完全に同期しているかどうか。", + "clientVersion": "接続されたノードで実行されているソフトウェアクライアントとバージョン。", + "protocolVersion": "接続されたノードがサポートするEthereumプロトコルバージョン。", + "currencyPrice": "このネットワークのネイティブ通貨の現在の市場価格。", + "latestBlock": "このネットワークで最も最近生成されたブロック。" }, "settings": { "knowledgeLevel": "エクスプローラー全体で表示される説明ヘルプの量を制御します。" diff --git a/src/locales/pt-BR/settings.json b/src/locales/pt-BR/settings.json index 88ec23e9..f72c290f 100644 --- a/src/locales/pt-BR/settings.json +++ b/src/locales/pt-BR/settings.json @@ -158,7 +158,7 @@ }, "knowledgeLevel": { "label": "Nível de Conhecimento", - "description": "Controla quantas dicas de ajuda são exibidas. Iniciante mostra mais, Avançado mostra menos.", + "description": "Controla quantas dicas de ajuda são exibidas. Iniciante mostra todas. Intermediário oculta campos básicos. Avançado mostra apenas dicas complexas e específicas da cadeia.", "beginner": "Iniciante", "intermediate": "Intermediário", "advanced": "Avançado" diff --git a/src/locales/pt-BR/tooltips.json b/src/locales/pt-BR/tooltips.json index 4fe7de03..757fc5b7 100644 --- a/src/locales/pt-BR/tooltips.json +++ b/src/locales/pt-BR/tooltips.json @@ -5,61 +5,76 @@ "status": "Se a transação foi executada com sucesso ou revertida.", "confirmations": "Blocos minerados após esta transação. Mais confirmações significa maior finalidade.", "interactedWith": "O contrato com o qual esta transação interagiu, ou o endereço do destinatário em transferências simples.", - "transactionFee": "Taxa total paga para processar esta transação (gas usado × preço do gas).", + "transactionFee": "Taxa total paga para processar esta transação (gas usado × preço do gas). O gas mede o trabalho computacional na rede, e sob o EIP-1559 as taxas incluem uma taxa base (queimada) mais uma taxa de prioridade (gorjeta).", "gasPrice": "Preço por unidade de gas, em Gwei. Preços mais altos incentivam inclusão mais rápida.", "gasLimitUsage": "O limite de gas é o máximo autorizado. O gas usado é a quantidade real consumida.", - "nonce": "Contador de transações do remetente. Garante que as transações sejam processadas em ordem.", + "nonce": "Contador de transações do remetente. Garante que as transações sejam processadas em ordem e previne ataques de repetição.", "position": "O índice desta transação dentro do seu bloco. Posições mais baixas foram processadas primeiro.", "type": "O formato da transação (ex: Legacy, EIP-1559, EIP-4844). Determina quais campos de taxa se aplicam.", "decodedInput": "A chamada de função e parâmetros enviados ao contrato, decodificados em formato legível.", "maxFeePerBlobGas": "Preço máximo por unidade de blob gas que o remetente está disposto a pagar pela disponibilidade de dados.", "blobGasPrice": "Preço real por unidade de blob gas pago neste bloco.", - "blobGasUsed": "Quantidade de blob gas consumido pelos blobs de dados desta transação.", - "blobCount": "Número de blobs de dados anexados a esta transação para disponibilidade de dados de rollup.", + "blobGasUsed": "Quantidade de blob gas consumido pelos blobs de dados desta transação. Blobs são contêineres de dados introduzidos no EIP-4844 para disponibilidade de dados de rollup, com preço separado do gas de execução.", + "blobCount": "Número de contêineres de dados anexados a esta transação para disponibilidade de dados de rollup.", "blobVersionedHashes": "Hashes versionados que identificam exclusivamente cada blob de dados comprometido por esta transação.", "contractCreated": "O endereço do novo contrato implantado por esta transação.", "value": "Quantidade de moeda nativa (ex: ETH) transferida nesta transação.", "effectiveGasPrice": "O preço de gas realmente pago após o cálculo de taxa EIP-1559, que pode diferir do preço solicitado.", "l1BlockNumber": "O bloco Ethereum L1 que ancora esta transação L2 para segurança.", "gasUsedForL1": "Gas consumido para publicar os dados desta transação no Ethereum L1.", - "l1Fee": "Taxa paga pela disponibilidade de dados no Ethereum L1. Parte do custo total da transação nesta L2.", + "l1Fee": "Taxa paga pela disponibilidade de dados no Ethereum L1. Redes L2 dependem da L1 para publicar dados de transações por segurança e verificação.", "l1GasPrice": "O preço de gas L1 usado para calcular o componente de taxa de disponibilidade de dados.", "l1GasUsed": "Gas L1 estimado necessário para publicar o calldata desta transação.", - "l1FeeScalar": "Um multiplicador aplicado ao cálculo da taxa L1 pelo sequenciador L2." + "l1FeeScalar": "Um multiplicador aplicado ao cálculo da taxa L1 pelo sequenciador L2.", + "txHashColumn": "O hash único que identifica esta transação.", + "blockColumn": "O número do bloco em que esta transação foi incluída.", + "methodColumn": "A função do contrato inteligente chamada por esta transação.", + "fromColumn": "O endereço que enviou esta transação.", + "toColumn": "O endereço de destino desta transação.", + "valueColumn": "A quantidade de moeda nativa transferida.", + "statusColumn": "Se a transação teve sucesso ou falhou.", + "callTree": "Rastreamento de todas as chamadas internas feitas durante a execução desta transação.", + "gasProfiler": "Detalhamento do consumo de gas em cada chamada interna.", + "stateChanges": "Modificações no estado da blockchain (saldos, nonces, armazenamento) causadas por esta transação.", + "balanceChange": "Mudança no saldo de moeda nativa deste endereço causada pela transação.", + "nonceChange": "Mudança na contagem de transações (nonce) deste endereço.", + "codeDeployed": "Novo bytecode de contrato implantado neste endereço pela transação.", + "storageChange": "Um slot de armazenamento no estado do contrato que foi modificado pela transação." }, "block": { "hash": "Uma impressão digital única que identifica este bloco, derivada de seu conteúdo.", "transactions": "O número de transações incluídas e executadas neste bloco.", "withdrawals": "Saques de validadores processados neste bloco, retornando ETH em stake.", "feeRecipient": "O endereço que recebe as taxas prioritárias das transações neste bloco.", - "difficulty": "Dificuldade de mineração para este bloco. Sempre zero em redes proof-of-stake após o Merge.", + "difficulty": "Dificuldade de mineração para este bloco. Zero em redes proof-of-stake após o Merge. Em algumas redes L2, pode ser uma constante diferente de zero.", "totalDifficulty": "Dificuldade acumulada da cadeia até este bloco. Campo legado de proof-of-work.", "size": "O tamanho total dos dados do bloco em bytes.", "extraData": "Dados arbitrários definidos pelo produtor do bloco. Frequentemente contém identificadores de cliente ou pool.", "gasUsed": "Gas total consumido por todas as transações neste bloco.", "gasLimit": "Gas máximo permitido neste bloco, definindo sua capacidade.", - "baseFeePerGas": "Preço mínimo de gas para este bloco, definido pela rede com base na demanda (EIP-1559).", + "baseFeePerGas": "Preço mínimo de gas para este bloco, definido pela rede com base na demanda (EIP-1559). Esta taxa base é queimada.", "burntFees": "Taxas de transação permanentemente removidas de circulação via EIP-1559.", "blobGasUsed": "Blob gas total consumido por transações blob neste bloco.", "excessBlobGas": "Blob gas acima do alvo, usado para calcular a taxa base blob do próximo bloco.", - "blobCount": "Número de blobs de dados incluídos neste bloco para disponibilidade de dados de rollup.", + "blobCount": "Número de contêineres de dados incluídos neste bloco para disponibilidade de dados de rollup.", "l1BlockNumber": "O número do bloco Ethereum L1 associado a este bloco Arbitrum.", "sendCount": "Número de mensagens de saída L2-para-L1 enviadas neste bloco Arbitrum.", "sendRoot": "Raiz de Merkle de todas as mensagens de saída L2-para-L1, usada para verificação entre camadas.", "parentHash": "Hash do bloco anterior na cadeia, ligando os blocos entre si.", - "stateRoot": "Raiz de Merkle de todo o estado da blockchain após processar este bloco.", + "stateRoot": "Raiz de Merkle de todo o estado da blockchain (um resumo criptográfico de todos os dados de contas) após processar este bloco.", "transactionsRoot": "Raiz de Merkle de todas as transações incluídas neste bloco.", "receiptsRoot": "Raiz de Merkle de todos os recibos de transações deste bloco.", "withdrawalsRoot": "Raiz de Merkle de todos os saques de validadores processados neste bloco.", - "logsBloom": "Um filtro bloom para buscar eficientemente logs de eventos emitidos neste bloco.", + "logsBloom": "Um filtro bloom (estrutura de dados probabilística) para buscar eficientemente logs de eventos emitidos neste bloco.", "nonce": "Um valor usado na mineração proof-of-work. Sempre zero após o Merge.", "mixHash": "Um hash usado no algoritmo proof-of-work. Substituído pelo valor RANDAO após o Merge.", "sha3Uncles": "Hash da lista de blocos uncle. Sempre o hash de lista vazia após o Merge.", - "validator": "O índice do validador que iniciou esta retirada da beacon chain." + "validator": "O índice do validador que iniciou esta retirada da beacon chain.", + "finalized": "Este bloco foi finalizado pelo mecanismo de consenso da rede e não pode ser revertido." }, "address": { "verification": "Um contrato verificado tem seu código-fonte publicamente confirmado como correspondente ao bytecode implantado.", - "proxyType": "Este contrato usa um padrão de proxy atualizável. A lógica está em um contrato de implementação separado.", + "proxyType": "Este contrato usa um padrão de proxy atualizável, onde a execução é delegada a um contrato de implementação separado, permitindo atualizações sem alterar o endereço.", "readContract": "Consultar dados do contrato sem gastar gas ou conectar uma carteira. Chamadas somente leitura.", "writeContract": "Enviar uma transação que altera o estado do contrato. Requer uma carteira conectada e gas.", "balance": "Saldo de moeda nativa mantido por este endereço.", @@ -67,8 +82,13 @@ "nonce": "Número de transações enviadas a partir deste endereço. Usado para ordenação de transações.", "eip7702Delegate": "Esta conta delega a execução de seu código a outro endereço via EIP-7702.", "implementationAddress": "O contrato que contém a lógica real deste proxy.", - "ensName": "Nome do Ethereum Name Service associado a este endereço.", - "ensApp": "Aplicação ou resolvedor vinculado a este nome ENS." + "ensName": "Nome do Ethereum Name Service (mapeia nomes legíveis para endereços) associado a este endereço.", + "ensApp": "Aplicação ou resolvedor vinculado a este nome ENS.", + "accountType": "O tipo deste endereço. EOA (Conta de Propriedade Externa) é uma carteira regular controlada por uma chave privada. Contrato é código implantado na cadeia.", + "contractBytecode": "O bytecode EVM compilado implantado neste endereço.", + "sourceCode": "O código-fonte original em Solidity/Vyper, verificado para corresponder ao bytecode implantado.", + "rawAbi": "A Interface Binária de Aplicação (ABI) define como interagir com as funções deste contrato.", + "functions": "Funções de contrato disponíveis que podem ser chamadas para ler dados ou modificar o estado." }, "token": { "tokenStandard": "O padrão de interface do token (ex: ERC-20, ERC-721, ERC-1155) que define como este token se comporta.", @@ -84,7 +104,7 @@ "witnessHash": "Hash da transação incluindo dados witness (SegWit). Difere do TXID para transações SegWit.", "block": "O bloco que inclui esta transação.", "status": "Se esta transação foi confirmada em um bloco ou ainda está esperando no mempool.", - "inputs": "O número de saídas anteriores sendo gastas. Cada entrada referencia um UTXO.", + "inputs": "O número de saídas anteriores sendo gastas. Cada entrada referencia um UTXO. Bitcoin usa um modelo UTXO onde transações consomem e criam saídas discretas.", "outputs": "O número de novas saídas criadas. Cada saída bloqueia BTC para um endereço.", "fee": "A diferença entre entradas e saídas totais, paga ao minerador.", "feePerByte": "Taxa de tarifa em satoshis por byte de dados brutos da transação.", @@ -111,7 +131,7 @@ "previousBlock": "Hash do bloco anterior, ligando este bloco à cadeia.", "nextBlock": "Hash do bloco seguinte, se existir.", "coinbaseMessage": "Texto arbitrário incorporado na transação coinbase pelo minerador.", - "merkleRoot": "Hash raiz da árvore de Merkle de todas as transações neste bloco.", + "merkleRoot": "Hash raiz da árvore de Merkle (uma estrutura que permite verificação eficiente) de todas as transações neste bloco.", "blockVersion": "Versão do formato do bloco. Codifica quais regras de consenso e soft forks são sinalizados.", "bits": "Codificação compacta do limiar alvo para um hash de bloco válido.", "blockNonce": "Um valor que mineradores iteram para encontrar um hash de bloco abaixo do alvo.", @@ -120,7 +140,20 @@ "balance": "BTC total mantido por este endereço em todas as saídas não gastas.", "totalReceived": "BTC cumulativo recebido por este endereço em todas as transações.", "utxos": "Saídas de Transação Não Gastas. Moedas individuais disponíveis para gasto por este endereço.", - "txCount": "Número total de transações envolvendo este endereço." + "txCount": "Número total de transações envolvendo este endereço.", + "blockConfirmations": "Blocos minerados após este bloco. Mais confirmações significa que o bloco está mais profundamente incorporado na cadeia.", + "confirmations": "Blocos minerados após o bloco que contém esta transação. Mais confirmações significa maior finalidade.", + "inputsColumn": "Saídas de transações anteriores sendo gastas. Cada entrada referencia um UTXO (Saída de Transação Não Gasta).", + "outputsColumn": "Novas saídas criadas por esta transação. Cada saída bloqueia BTC para um endereço receptor." + }, + "network": { + "gasPrice": "Custo atual por unidade de gas nesta rede.", + "blockNumber": "O número do bloco mais recentemente minerado nesta rede.", + "syncStatus": "Se o nó conectado sincronizou completamente com a rede.", + "clientVersion": "O software cliente e versão executando no nó conectado.", + "protocolVersion": "A versão do protocolo Ethereum suportada pelo nó conectado.", + "currencyPrice": "Preço de mercado atual da moeda nativa desta rede.", + "latestBlock": "O bloco mais recentemente produzido nesta rede." }, "settings": { "knowledgeLevel": "Controla quanta ajuda explicativa é exibida no explorador." diff --git a/src/locales/zh/settings.json b/src/locales/zh/settings.json index c880864f..b436ffdc 100644 --- a/src/locales/zh/settings.json +++ b/src/locales/zh/settings.json @@ -158,7 +158,7 @@ }, "knowledgeLevel": { "label": "知识水平", - "description": "控制显示多少帮助提示。初学者显示最多,高级显示最少。", + "description": "控制显示多少帮助提示。初学者显示所有提示。中级隐藏基本字段。高级仅显示复杂和链特定的提示。", "beginner": "初学者", "intermediate": "中级", "advanced": "高级" diff --git a/src/locales/zh/tooltips.json b/src/locales/zh/tooltips.json index 9136700b..7a0deba2 100644 --- a/src/locales/zh/tooltips.json +++ b/src/locales/zh/tooltips.json @@ -5,61 +5,76 @@ "status": "交易是否成功执行或已回滚。", "confirmations": "此交易之后挖出的区块数。更多确认意味着更高的最终性。", "interactedWith": "此交易调用的合约,或简单转账的接收地址。", - "transactionFee": "处理此交易支付的总费用(使用的Gas × Gas价格)。", + "transactionFee": "处理此交易支付的总费用(使用的Gas × Gas价格)。Gas衡量网络上的计算工作,在EIP-1559下费用包括基础费用(销毁)加上优先费用(小费)。", "gasPrice": "每单位Gas的价格,以Gwei为单位。更高的Gas价格可以更快被打包。", "gasLimitUsage": "Gas限制是授权的最大Gas量。已用Gas是实际消耗的量。", - "nonce": "发送者的交易计数器。确保交易按顺序处理。", + "nonce": "发送者的交易计数器。确保交易按顺序处理并防止重放攻击。", "position": "此交易在区块中的索引。较低的位置优先处理。", "type": "交易格式(如Legacy、EIP-1559、EIP-4844)。决定适用哪些费用字段。", "decodedInput": "发送给合约的函数调用和参数,解码为可读格式。", "maxFeePerBlobGas": "发送者愿意为数据可用性支付的每单位Blob Gas最高价格。", "blobGasPrice": "此区块中实际支付的每单位Blob Gas价格。", - "blobGasUsed": "此交易的数据Blob消耗的Blob Gas量。", - "blobCount": "附加到此交易的数据Blob数量,用于Rollup数据可用性。", + "blobGasUsed": "此交易的数据Blob消耗的Blob Gas量。Blob是EIP-4844中引入的用于Rollup数据可用性的数据容器,与执行Gas分开定价。", + "blobCount": "附加到此交易的数据容器数量,用于Rollup数据可用性。", "blobVersionedHashes": "唯一标识此交易提交的每个数据Blob的版本化哈希。", "contractCreated": "此交易部署的新合约地址。", "value": "此交易中转移的原生货币(如ETH)金额。", "effectiveGasPrice": "经EIP-1559费用计算后实际支付的Gas价格,可能与请求的价格不同。", "l1BlockNumber": "锚定此L2交易安全性的以太坊L1区块。", "gasUsedForL1": "将此交易数据发布到以太坊L1所消耗的Gas。", - "l1Fee": "在以太坊L1上为数据可用性支付的费用。是此L2上总交易成本的一部分。", + "l1Fee": "在以太坊L1上为数据可用性支付的费用。L2网络依赖L1发布交易数据以确保安全性和可验证性。", "l1GasPrice": "用于计算数据可用性费用的L1 Gas价格。", "l1GasUsed": "发布此交易calldata所需的预估L1 Gas。", - "l1FeeScalar": "L2排序器应用于L1费用计算的乘数。" + "l1FeeScalar": "L2排序器应用于L1费用计算的乘数。", + "txHashColumn": "标识此交易的唯一哈希。", + "blockColumn": "此交易被包含在的区块号。", + "methodColumn": "此交易调用的智能合约函数。", + "fromColumn": "发送此交易的地址。", + "toColumn": "此交易的目标地址。", + "valueColumn": "转移的原生货币数量。", + "statusColumn": "交易是否成功或失败。", + "callTree": "此交易执行期间所有内部调用的跟踪。", + "gasProfiler": "每个内部调用的Gas消耗详细分解。", + "stateChanges": "此交易导致的区块链状态修改(余额、nonce、存储)。", + "balanceChange": "交易导致此地址原生货币余额的变化。", + "nonceChange": "此地址的交易计数(nonce)变化。", + "codeDeployed": "交易在此地址部署的新合约字节码。", + "storageChange": "合约状态中被交易修改的存储槽。" }, "block": { "hash": "标识此区块的唯一指纹,由其内容派生。", "transactions": "此区块中包含和执行的交易数量。", "withdrawals": "此区块中处理的验证者提款,返回质押的ETH。", "feeRecipient": "接收此区块中交易优先费用的地址。", - "difficulty": "此区块的挖矿难度。在合并后的权益证明网络上始终为零。", + "difficulty": "此区块的挖矿难度。在合并后的权益证明网络上为零。在某些L2网络上,可能是非零常数。", "totalDifficulty": "到此区块为止的链累积难度。工作量证明的遗留字段。", "size": "区块数据的总大小(字节)。", "extraData": "区块生产者设置的任意数据。通常包含客户端或矿池标识符。", "gasUsed": "此区块中所有交易消耗的总Gas。", "gasLimit": "此区块允许的最大Gas量,定义其容量。", - "baseFeePerGas": "此区块的最低Gas价格,由网络根据需求设定(EIP-1559)。", + "baseFeePerGas": "此区块的最低Gas价格,由网络根据需求设定(EIP-1559)。此基础费用被销毁。", "burntFees": "通过EIP-1559永久从流通中移除的交易费用。", "blobGasUsed": "此区块中Blob交易消耗的总Blob Gas。", "excessBlobGas": "超出目标的Blob Gas,用于计算下一个区块的Blob基础费用。", - "blobCount": "此区块中包含的数据Blob数量,用于Rollup数据可用性。", + "blobCount": "此区块中包含的数据容器数量,用于Rollup数据可用性。", "l1BlockNumber": "与此Arbitrum区块关联的以太坊L1区块号。", "sendCount": "此Arbitrum区块中发送的L2到L1出站消息数量。", "sendRoot": "所有L2到L1出站消息的Merkle根,用于跨层验证。", "parentHash": "链中前一个区块的哈希,将区块链接在一起。", - "stateRoot": "处理此区块后整个区块链状态的Merkle根。", + "stateRoot": "处理此区块后整个区块链状态(所有账户数据的加密摘要)的Merkle根。", "transactionsRoot": "此区块中包含的所有交易的Merkle根。", "receiptsRoot": "此区块中所有交易收据的Merkle根。", "withdrawalsRoot": "此区块中处理的所有验证者提款的Merkle根。", - "logsBloom": "用于高效搜索此区块中发出的事件日志的布隆过滤器。", + "logsBloom": "用于高效搜索此区块中发出的事件日志的布隆过滤器(概率数据结构)。", "nonce": "工作量证明挖矿中使用的值。合并后始终为零。", "mixHash": "工作量证明算法中使用的哈希。合并后被RANDAO值替代。", "sha3Uncles": "叔块列表的哈希。合并后始终为空列表哈希。", - "validator": "从信标链发起此提款的验证者索引。" + "validator": "从信标链发起此提款的验证者索引。", + "finalized": "此区块已被网络的共识机制最终确认,无法被撤销。" }, "address": { "verification": "已验证的合约其源代码已被公开确认与部署的字节码匹配。", - "proxyType": "此合约使用可升级代理模式。逻辑位于单独的实现合约中。", + "proxyType": "此合约使用可升级代理模式,执行被委托给单独的实现合约,允许在不更改地址的情况下进行升级。", "readContract": "查询合约数据,无需消耗Gas或连接钱包。只读调用。", "writeContract": "发送改变合约状态的交易。需要连接钱包并消耗Gas。", "balance": "此地址持有的原生货币余额。", @@ -67,8 +82,13 @@ "nonce": "从此地址发送的交易数量。用于交易排序。", "eip7702Delegate": "此账户通过EIP-7702将其代码执行委托给另一个地址。", "implementationAddress": "包含此代理实际逻辑的合约。", - "ensName": "与此地址关联的以太坊名称服务名称。", - "ensApp": "与此ENS名称关联的应用或解析器。" + "ensName": "与此地址关联的以太坊名称服务(将人类可读名称映射到地址)名称。", + "ensApp": "与此ENS名称关联的应用或解析器。", + "accountType": "此地址的类型。EOA(外部拥有账户)是由私钥控制的普通钱包。合约是部署在链上的代码。", + "contractBytecode": "部署在此地址的编译后EVM字节码。", + "sourceCode": "经验证与部署字节码匹配的原始Solidity/Vyper源代码。", + "rawAbi": "应用程序二进制接口(ABI)定义了如何与此合约的函数进行交互。", + "functions": "可调用的合约函数,用于读取数据或修改状态。" }, "token": { "tokenStandard": "代币接口标准(如ERC-20、ERC-721、ERC-1155),定义了代币的行为方式。", @@ -84,7 +104,7 @@ "witnessHash": "包含见证(SegWit)数据的交易哈希。对于SegWit交易与TXID不同。", "block": "包含此交易的区块。", "status": "此交易是否已在区块中确认,或仍在内存池中等待。", - "inputs": "正在花费的先前输出数量。每个输入引用一个UTXO。", + "inputs": "正在花费的先前输出数量。每个输入引用一个UTXO。比特币使用UTXO模型,交易消耗和创建离散输出。", "outputs": "创建的新输出数量。每个输出将BTC锁定到一个地址。", "fee": "总输入与总输出之间的差额,支付给矿工。", "feePerByte": "每字节原始交易数据的费率(聪)。", @@ -111,7 +131,7 @@ "previousBlock": "前一个区块的哈希,将此区块链接到链上。", "nextBlock": "下一个区块的哈希(如果存在)。", "coinbaseMessage": "矿工在coinbase交易中嵌入的任意文本。", - "merkleRoot": "此区块中所有交易的Merkle树根哈希。", + "merkleRoot": "此区块中所有交易的Merkle树(允许高效验证的结构)根哈希。", "blockVersion": "区块格式版本。编码信号哪些共识规则和软分叉。", "bits": "有效区块哈希目标阈值的紧凑编码。", "blockNonce": "矿工迭代以找到低于目标的区块哈希的值。", @@ -120,7 +140,20 @@ "balance": "此地址在所有未花费输出中持有的BTC总量。", "totalReceived": "此地址在所有交易中累计收到的BTC。", "utxos": "未花费交易输出。此地址可用于花费的单个币。", - "txCount": "涉及此地址的交易总数。" + "txCount": "涉及此地址的交易总数。", + "blockConfirmations": "此区块后挖出的区块数。更多确认意味着区块在链中嵌入更深。", + "confirmations": "包含此交易的区块后挖出的区块数。更多确认意味着更高的最终性。", + "inputsColumn": "正在花费的先前交易输出。每个输入引用一个UTXO(未花费交易输出)。", + "outputsColumn": "此交易创建的新输出。每个输出将BTC锁定到接收地址。" + }, + "network": { + "gasPrice": "此网络每单位Gas的当前成本。", + "blockNumber": "此网络上最近挖出的区块号。", + "syncStatus": "连接的节点是否已与网络完全同步。", + "clientVersion": "连接节点上运行的软件客户端和版本。", + "protocolVersion": "连接节点支持的以太坊协议版本。", + "currencyPrice": "此网络原生货币的当前市场价格。", + "latestBlock": "此网络上最近产生的区块。" }, "settings": { "knowledgeLevel": "控制整个浏览器中显示的帮助说明数量。" diff --git a/src/styles/helper-tooltip.css b/src/styles/helper-tooltip.css index 1a6d6305..def820ea 100644 --- a/src/styles/helper-tooltip.css +++ b/src/styles/helper-tooltip.css @@ -37,11 +37,8 @@ border-radius: 50%; } -/* Tooltip bubble */ +/* Tooltip bubble — portaled to document.body, positioned via inline style */ .helper-tooltip-bubble { - position: absolute; - left: 50%; - transform: translateX(-50%); max-width: 260px; min-width: 140px; padding: 8px 12px; @@ -52,44 +49,12 @@ line-height: 1.45; border-radius: 6px; box-shadow: var(--shadow-md); - z-index: 1000; + z-index: 10000; pointer-events: auto; white-space: normal; word-wrap: break-word; } -/* Top placement (default) */ -.helper-tooltip-top { - bottom: calc(100% + 6px); -} - -.helper-tooltip-top::after { - content: ""; - position: absolute; - top: 100%; - left: 50%; - transform: translateX(-50%); - border-width: 5px; - border-style: solid; - border-color: var(--bg-tooltip) transparent transparent transparent; -} - -/* Bottom placement */ -.helper-tooltip-bottom { - top: calc(100% + 6px); -} - -.helper-tooltip-bottom::after { - content: ""; - position: absolute; - bottom: 100%; - left: 50%; - transform: translateX(-50%); - border-width: 5px; - border-style: solid; - border-color: transparent transparent var(--bg-tooltip) transparent; -} - /* Light theme text: keep tooltip text white since bg-tooltip is dark in both themes */ .light-theme .helper-tooltip-bubble { color: #fff; @@ -114,15 +79,5 @@ .helper-tooltip-bubble { max-width: 220px; font-size: 0.78rem; - left: auto; - right: -8px; - transform: none; - } - - .helper-tooltip-top::after, - .helper-tooltip-bottom::after { - left: auto; - right: 12px; - transform: none; } } From 234cfbd7e2a6cef4f80037c4ac96b3b7982d8c18 Mon Sep 17 00:00:00 2001 From: Augusto Lemble Date: Thu, 19 Mar 2026 12:10:59 -0300 Subject: [PATCH 3/7] refactor(bitcoin): rearrange tx detail columns layout Move coinbase and witness to left column, RBF to right column for better visual grouping of related fields. --- .../bitcoin/BitcoinTransactionDisplay.tsx | 57 ++++++++++--------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx b/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx index 5d7bd5ed..9a7c66e6 100644 --- a/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx +++ b/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx @@ -300,6 +300,35 @@ const BitcoinTransactionDisplay: React.FC = Reac
    )} + +
    + + + {isCoinbase ? ( + Yes + ) : ( + No + )} + +
    +
    + + + {witnessEnabled ? ( + Yes + ) : ( + No + )} + +
    {/* Right Column */} @@ -331,34 +360,6 @@ const BitcoinTransactionDisplay: React.FC = Reac {transaction.weight.toLocaleString()} WU
    -
    - - - {isCoinbase ? ( - Yes - ) : ( - No - )} - -
    -
    - - - {witnessEnabled ? ( - Yes - ) : ( - No - )} - -
    Date: Thu, 19 Mar 2026 12:19:51 -0300 Subject: [PATCH 4/7] feat(bitcoin): show block number alongside hash on tx page Fetch block height from block header when displaying confirmed transactions. Block number is shown as plain text before the clickable block hash link. --- .../pages/bitcoin/BitcoinTransactionDisplay.tsx | 9 ++++++--- .../adapters/BitcoinAdapter/BitcoinAdapter.ts | 16 +++++++++++++++- src/types/index.ts | 1 + 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx b/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx index 9a7c66e6..b9cdbc12 100644 --- a/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx +++ b/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx @@ -180,16 +180,19 @@ const BitcoinTransactionDisplay: React.FC = Reac {transaction.blockhash && (
    - + + {transaction.blockheight !== undefined && ( + {transaction.blockheight.toLocaleString()} - + )} {networkId ? ( {truncateBlockHash(transaction.blockhash)} ) : ( - truncateBlockHash(transaction.blockhash) + {truncateBlockHash(transaction.blockhash)} )}
    diff --git a/src/services/adapters/BitcoinAdapter/BitcoinAdapter.ts b/src/services/adapters/BitcoinAdapter/BitcoinAdapter.ts index e44b86ca..3eb59478 100644 --- a/src/services/adapters/BitcoinAdapter/BitcoinAdapter.ts +++ b/src/services/adapters/BitcoinAdapter/BitcoinAdapter.ts @@ -593,8 +593,22 @@ export class BitcoinAdapter { } } + const tx = this.transformTransaction(txData); + + // Fetch block height from block header when we have a blockhash + if (tx.blockhash) { + try { + const headerResult = await this.client.getBlockHeader(tx.blockhash, true); + if (headerResult.data?.height !== undefined) { + tx.blockheight = headerResult.data.height; + } + } catch { + // Block header not available, continue without height + } + } + return { - data: this.transformTransaction(txData), + data: tx, metadata: metadata as DataWithMetadata["metadata"], }; } diff --git a/src/types/index.ts b/src/types/index.ts index c7b1be33..50f45a27 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -228,6 +228,7 @@ export interface BitcoinTransaction { vin: BitcoinTransactionInput[]; vout: BitcoinTransactionOutput[]; blockhash?: string; + blockheight?: number; confirmations?: number; blocktime?: number; time?: number; From 1a787a8d01a943495544ef79b530fe6646fa26cb Mon Sep 17 00:00:00 2001 From: Augusto Lemble Date: Thu, 19 Mar 2026 12:26:26 -0300 Subject: [PATCH 5/7] feat(tooltips): add left and right placement options Support all four directions (top, bottom, left, right) for tooltip bubbles. Use left placement for confirmation and finalized badges in the top-right corner. Add vertical viewport clamping. --- src/components/common/HelperTooltip.tsx | 65 ++++++++++++++----- .../pages/bitcoin/BitcoinBlockDisplay.tsx | 2 +- .../bitcoin/BitcoinTransactionDisplay.tsx | 2 +- .../pages/evm/block/BlockDisplay.tsx | 2 +- 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/src/components/common/HelperTooltip.tsx b/src/components/common/HelperTooltip.tsx index 53e1a55a..07ab9f9d 100644 --- a/src/components/common/HelperTooltip.tsx +++ b/src/components/common/HelperTooltip.tsx @@ -3,7 +3,7 @@ import { createPortal } from "react-dom"; interface HelperTooltipProps { content: string; - placement?: "top" | "bottom"; + placement?: "top" | "bottom" | "left" | "right"; className?: string; } @@ -22,7 +22,12 @@ const HelperTooltip: React.FC = ({ content, placement = "top const show = useCallback(() => { if (triggerRef.current) { const rect = triggerRef.current.getBoundingClientRect(); - setActualPlacement(rect.top < 80 ? "bottom" : placement); + // Only auto-flip top↔bottom; left/right stay as requested + if (placement === "top" || placement === "bottom") { + setActualPlacement(rect.top < 80 ? "bottom" : placement); + } else { + setActualPlacement(placement); + } setTriggerRect(rect); } setIsVisible(true); @@ -120,35 +125,59 @@ const HelperTooltip: React.FC = ({ content, placement = "top const rect = bubble.getBoundingClientRect(); const margin = 8; + // Horizontal clamping if (rect.right > window.innerWidth - margin) { bubble.style.left = `${window.innerWidth - margin - rect.width}px`; bubble.style.transform = "none"; - } - if (rect.left < margin) { + } else if (rect.left < margin) { bubble.style.left = `${margin}px`; bubble.style.transform = "none"; } + + // Vertical clamping + if (rect.bottom > window.innerHeight - margin) { + bubble.style.top = `${window.innerHeight - margin - rect.height}px`; + } else if (rect.top < margin) { + bubble.style.top = `${margin}px`; + } }, [isVisible, triggerRect]); const getBubbleStyle = (): React.CSSProperties => { if (!triggerRect) return {}; const gap = 6; const centerX = triggerRect.left + triggerRect.width / 2; - - if (actualPlacement === "bottom") { - return { - position: "fixed", - top: triggerRect.bottom + gap, - left: centerX, - transform: "translateX(-50%)", - }; + const centerY = triggerRect.top + triggerRect.height / 2; + + switch (actualPlacement) { + case "bottom": + return { + position: "fixed", + top: triggerRect.bottom + gap, + left: centerX, + transform: "translateX(-50%)", + }; + case "left": + return { + position: "fixed", + top: centerY, + left: triggerRect.left - gap, + transform: "translate(-100%, -50%)", + }; + case "right": + return { + position: "fixed", + top: centerY, + left: triggerRect.right + gap, + transform: "translateY(-50%)", + }; + default: + return { + position: "fixed", + top: triggerRect.top - gap, + left: centerX, + transform: "translate(-50%, -100%)", + }; } - return { - position: "fixed", - top: triggerRect.top - gap, - left: centerX, - transform: "translate(-50%, -100%)", - }; }; const bubble = isVisible ? ( diff --git a/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx b/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx index c8a9f861..4bfde466 100644 --- a/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx +++ b/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx @@ -93,7 +93,7 @@ const BitcoinBlockDisplay: React.FC = React.memo( {block.confirmations.toLocaleString()} Confirmations {settings.showHelperTooltips !== false && ( - + )} )} diff --git a/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx b/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx index b9cdbc12..94cc849a 100644 --- a/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx +++ b/src/components/pages/bitcoin/BitcoinTransactionDisplay.tsx @@ -136,7 +136,7 @@ const BitcoinTransactionDisplay: React.FC = Reac {transaction.confirmations.toLocaleString()} Confirmations {settings.showHelperTooltips !== false && ( - + )} ) diff --git a/src/components/pages/evm/block/BlockDisplay.tsx b/src/components/pages/evm/block/BlockDisplay.tsx index 9d37f770..4cb77c7c 100644 --- a/src/components/pages/evm/block/BlockDisplay.tsx +++ b/src/components/pages/evm/block/BlockDisplay.tsx @@ -164,7 +164,7 @@ const BlockDisplay: React.FC = React.memo( {t("finalized")} {settings.showHelperTooltips !== false && ( - + )}
    From 443b300a082b49a5aa862501bf0caed7f7412800 Mon Sep 17 00:00:00 2001 From: Augusto Lemble Date: Thu, 19 Mar 2026 12:30:52 -0300 Subject: [PATCH 6/7] fix(tooltips): prevent bubble from overlapping trigger on viewport clamp Compute final pixel position for both axes before removing transform, so vertical translation is preserved when only horizontal clamping is needed and vice versa. --- src/components/common/HelperTooltip.tsx | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/components/common/HelperTooltip.tsx b/src/components/common/HelperTooltip.tsx index 07ab9f9d..e4d4c254 100644 --- a/src/components/common/HelperTooltip.tsx +++ b/src/components/common/HelperTooltip.tsx @@ -124,21 +124,32 @@ const HelperTooltip: React.FC = ({ content, placement = "top const bubble = bubbleRef.current; const rect = bubble.getBoundingClientRect(); const margin = 8; + let needsClamp = false; + let left = rect.left; + let top = rect.top; // Horizontal clamping if (rect.right > window.innerWidth - margin) { - bubble.style.left = `${window.innerWidth - margin - rect.width}px`; - bubble.style.transform = "none"; + left = window.innerWidth - margin - rect.width; + needsClamp = true; } else if (rect.left < margin) { - bubble.style.left = `${margin}px`; - bubble.style.transform = "none"; + left = margin; + needsClamp = true; } // Vertical clamping if (rect.bottom > window.innerHeight - margin) { - bubble.style.top = `${window.innerHeight - margin - rect.height}px`; + top = window.innerHeight - margin - rect.height; + needsClamp = true; } else if (rect.top < margin) { - bubble.style.top = `${margin}px`; + top = margin; + needsClamp = true; + } + + if (needsClamp) { + bubble.style.left = `${left}px`; + bubble.style.top = `${top}px`; + bubble.style.transform = "none"; } }, [isVisible, triggerRect]); From cfc9998625960647955005b805f53d65072bc1b9 Mon Sep 17 00:00:00 2001 From: Augusto Lemble Date: Thu, 19 Mar 2026 12:33:38 -0300 Subject: [PATCH 7/7] feat(tooltips): add arrow pointer from bubble to trigger Render a CSS triangle arrow inside the tooltip bubble that points toward the trigger. Arrow position is dynamically calculated after viewport clamping to always aim at the trigger center. --- src/components/common/HelperTooltip.tsx | 35 ++++++++++++++++-- .../pages/bitcoin/BitcoinBlockDisplay.tsx | 5 ++- src/styles/helper-tooltip.css | 37 +++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/components/common/HelperTooltip.tsx b/src/components/common/HelperTooltip.tsx index e4d4c254..58dc1f7e 100644 --- a/src/components/common/HelperTooltip.tsx +++ b/src/components/common/HelperTooltip.tsx @@ -16,6 +16,7 @@ const HelperTooltip: React.FC = ({ content, placement = "top const tooltipId = useId(); const triggerRef = useRef(null); const bubbleRef = useRef(null); + const arrowRef = useRef(null); const hoverTimeoutRef = useRef | null>(null); const isPointerInsideRef = useRef(false); @@ -118,10 +119,11 @@ const HelperTooltip: React.FC = ({ content, placement = "top }; }, []); - // Clamp bubble within viewport after render + // Clamp bubble within viewport and position arrow after render useLayoutEffect(() => { - if (!isVisible || !bubbleRef.current) return; + if (!isVisible || !bubbleRef.current || !triggerRect) return; const bubble = bubbleRef.current; + const arrow = arrowRef.current; const rect = bubble.getBoundingClientRect(); const margin = 8; let needsClamp = false; @@ -151,7 +153,29 @@ const HelperTooltip: React.FC = ({ content, placement = "top bubble.style.top = `${top}px`; bubble.style.transform = "none"; } - }, [isVisible, triggerRect]); + + // Position arrow to point at trigger center + if (arrow) { + const bubbleRect = bubble.getBoundingClientRect(); + const triggerCenterX = triggerRect.left + triggerRect.width / 2; + const triggerCenterY = triggerRect.top + triggerRect.height / 2; + const arrowSize = 5; + + if (actualPlacement === "top" || actualPlacement === "bottom") { + const arrowLeft = Math.max( + arrowSize, + Math.min(triggerCenterX - bubbleRect.left, bubbleRect.width - arrowSize), + ); + arrow.style.left = `${arrowLeft}px`; + } else { + const arrowTop = Math.max( + arrowSize, + Math.min(triggerCenterY - bubbleRect.top, bubbleRect.height - arrowSize), + ); + arrow.style.top = `${arrowTop}px`; + } + } + }, [isVisible, triggerRect, actualPlacement]); const getBubbleStyle = (): React.CSSProperties => { if (!triggerRect) return {}; @@ -202,6 +226,11 @@ const HelperTooltip: React.FC = ({ content, placement = "top onMouseLeave={handlePointerLeave} > {content} +
    ) : null; diff --git a/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx b/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx index 4bfde466..a7ab57aa 100644 --- a/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx +++ b/src/components/pages/bitcoin/BitcoinBlockDisplay.tsx @@ -93,7 +93,10 @@ const BitcoinBlockDisplay: React.FC = React.memo( {block.confirmations.toLocaleString()} Confirmations {settings.showHelperTooltips !== false && ( - + )} )} diff --git a/src/styles/helper-tooltip.css b/src/styles/helper-tooltip.css index def820ea..448d2a87 100644 --- a/src/styles/helper-tooltip.css +++ b/src/styles/helper-tooltip.css @@ -55,6 +55,43 @@ word-wrap: break-word; } +/* Arrow pointing from bubble to trigger */ +.helper-tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border: 5px solid transparent; + pointer-events: none; +} + +/* Top placement: arrow at bottom, pointing down */ +.helper-tooltip-arrow-top { + bottom: -10px; + transform: translateX(-50%); + border-top-color: var(--bg-tooltip); +} + +/* Bottom placement: arrow at top, pointing up */ +.helper-tooltip-arrow-bottom { + top: -10px; + transform: translateX(-50%); + border-bottom-color: var(--bg-tooltip); +} + +/* Left placement: arrow at right, pointing right */ +.helper-tooltip-arrow-left { + right: -10px; + transform: translateY(-50%); + border-left-color: var(--bg-tooltip); +} + +/* Right placement: arrow at left, pointing left */ +.helper-tooltip-arrow-right { + left: -10px; + transform: translateY(-50%); + border-right-color: var(--bg-tooltip); +} + /* Light theme text: keep tooltip text white since bg-tooltip is dark in both themes */ .light-theme .helper-tooltip-bubble { color: #fff;
    TX HashBlockMethodFromToValueStatus + TX Hash + {settings.showHelperTooltips !== false && ( + + )} + + Block + {settings.showHelperTooltips !== false && ( + + )} + + Method + {settings.showHelperTooltips !== false && ( + + )} + + From + {settings.showHelperTooltips !== false && ( + + )} + + To + {settings.showHelperTooltips !== false && ( + + )} + + Value + {settings.showHelperTooltips !== false && ( + + )} + + Status + {settings.showHelperTooltips !== false && ( + + )} +