From 656c8fba4469e8e1efcf3910092819961a3d7634 Mon Sep 17 00:00:00 2001 From: Dan Rusnac Date: Wed, 1 Jul 2026 17:02:21 +0200 Subject: [PATCH] feat: agent-aware view on the NFT detail page Detect agent-marketplace NFTs (ERC-8004 registration files) on the existing /nft/[contractAddress]/[tokenId] page and render a tabbed agent view: Overview, Services, Statistics, Quality, Feedback, and Metadata. Non-agent NFTs are unaffected. Detection keys off the tokenURI JSON's `type` marker (https://eips.ethereum.org/EIPS/eip-8004#registration-v1). All data is read on-chain / from the metadata the token points at: - Registration file (tokenURI) -> Overview, Services, Metadata - A2A AgentCard, fetched from the registration file's `A2A` service endpoint (.../agent-card.json) -> Services (skills, capabilities, modes) - AgentRegistry.getAgent (the NFT contract == the registry, tokenId == agentId) -> creator, status - ReputationRegistry (address taken from the registration file) getClients / getSummary / readAllFeedback -> Statistics, Quality, Feedback Reputation-backed tabs degrade to empty states when no feedback exists. Adds i18n keys across all 11 locales and unit tests for the schema, detection, A2A endpoint resolution, and CAIP-10 address parsing. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../components/NftDetailPageContent.tsx | 22 ++- .../components/agent/AgentDetail.tsx | 50 ++++++ .../components/agent/AgentNftView.tsx | 125 +++++++++++++++ .../components/agent/tabs/FeedbackTab.tsx | 80 ++++++++++ .../components/agent/tabs/MetadataTab.tsx | 60 ++++++++ .../components/agent/tabs/OverviewTab.tsx | 80 ++++++++++ .../components/agent/tabs/QualityTab.tsx | 57 +++++++ .../components/agent/tabs/ServicesTab.tsx | 128 ++++++++++++++++ .../components/agent/tabs/StatisticsTab.tsx | 58 +++++++ i18n/languages/de.json | 43 ++++++ i18n/languages/el.json | 43 ++++++ i18n/languages/en.json | 53 ++++++- i18n/languages/es.json | 43 ++++++ i18n/languages/fr.json | 43 ++++++ i18n/languages/it.json | 43 ++++++ i18n/languages/ja.json | 43 ++++++ i18n/languages/pt.json | 43 ++++++ i18n/languages/ru.json | 43 ++++++ i18n/languages/tr.json | 43 ++++++ i18n/languages/zh.json | 43 ++++++ services/agent-nft/hooks.ts | 58 +++++++ services/agent-nft/schemas.spec.ts | 125 +++++++++++++++ services/agent-nft/schemas.ts | 96 ++++++++++++ services/thor/tokens/agent-registry.ts | 72 +++++++++ services/thor/tokens/reputation-registry.ts | 145 ++++++++++++++++++ 25 files changed, 1633 insertions(+), 6 deletions(-) create mode 100644 app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/AgentDetail.tsx create mode 100644 app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/AgentNftView.tsx create mode 100644 app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/FeedbackTab.tsx create mode 100644 app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/MetadataTab.tsx create mode 100644 app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/OverviewTab.tsx create mode 100644 app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/QualityTab.tsx create mode 100644 app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/ServicesTab.tsx create mode 100644 app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/StatisticsTab.tsx create mode 100644 services/agent-nft/hooks.ts create mode 100644 services/agent-nft/schemas.spec.ts create mode 100644 services/agent-nft/schemas.ts create mode 100644 services/thor/tokens/agent-registry.ts create mode 100644 services/thor/tokens/reputation-registry.ts diff --git a/app/[locale]/nft/[contractAddress]/[tokenId]/components/NftDetailPageContent.tsx b/app/[locale]/nft/[contractAddress]/[tokenId]/components/NftDetailPageContent.tsx index 77dd4898..9e21bbf3 100644 --- a/app/[locale]/nft/[contractAddress]/[tokenId]/components/NftDetailPageContent.tsx +++ b/app/[locale]/nft/[contractAddress]/[tokenId]/components/NftDetailPageContent.tsx @@ -5,8 +5,10 @@ import { useTranslation } from 'react-i18next' import { NotFound } from '@/components/error/NotFound' import { Card } from '@/components/ui/Card' import type { AddressString } from '@/lib/schemas' +import { useAgentRegistration } from '@/services/agent-nft/hooks' import { parseNftMetadataUri, useNftMetadata } from '@/services/nft-metadata' import { useErc721Contract, useErc721Token } from '@/services/thor/tokens/erc721' +import { AgentNftView } from './agent/AgentNftView' import { NftDetailHeader } from './NftDetailHeader' import { NftStatsCards } from './NftStatsCards' import { NftDetailsSection } from './NftDetailsSection' @@ -27,8 +29,11 @@ export const NftDetailPageContent = ({ tokenId, }) const { data: metadata, isPending: isMetadataPending } = useNftMetadata(token?.tokenUri ?? '') + const { data: agentRegistration, isPending: isAgentRegistrationPending } = useAgentRegistration({ + tokenUri: token?.tokenUri, + }) - const isPending = isCollectionPending || isTokenPending + const isPending = isCollectionPending || isTokenPending || (!!token?.tokenUri && isAgentRegistrationPending) if (isPending) { return ( @@ -45,6 +50,21 @@ export const NftDetailPageContent = ({ const nftImage = metadata?.image ? parseNftMetadataUri(metadata.image) : '/no-image.png' const nftName = metadata?.name || `#${tokenId.toString()}` + // Agent NFTs (ERC-8004 registration file at tokenURI) get a dedicated tabbed view. + if (agentRegistration) { + const agentImage = agentRegistration.image ? parseNftMetadataUri(agentRegistration.image) : nftImage + return ( + + ) + } + return ( diff --git a/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/AgentDetail.tsx b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/AgentDetail.tsx new file mode 100644 index 00000000..ab3f06a1 --- /dev/null +++ b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/AgentDetail.tsx @@ -0,0 +1,50 @@ +'use client' + +import { Box, EmptyState, Flex, Stack, Text } from '@chakra-ui/react' +import { LuInbox } from 'react-icons/lu' + +/** Label/value row used across the agent tabs. Mirrors the NFT details layout. */ +export const DetailRow = ({ label, children }: { label: string; children: React.ReactNode }) => ( + + + {label} + + + {children} + + +) + +/** Titled, bordered container grouping a set of rows. */ +export const SectionCard = ({ title, children }: { title: string; children: React.ReactNode }) => ( + + + {title} + + + {children} + + +) + +/** Shared empty-state placeholder for reputation-backed tabs with no data yet. */ +export const AgentEmptyState = ({ title, description }: { title: string; description: string }) => ( + + + + + + {title} + {description} + + +) diff --git a/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/AgentNftView.tsx b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/AgentNftView.tsx new file mode 100644 index 00000000..2979b6df --- /dev/null +++ b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/AgentNftView.tsx @@ -0,0 +1,125 @@ +'use client' + +import { Badge, Flex, Grid, Heading, Stack, Tabs } from '@chakra-ui/react' +import { useTranslation } from 'react-i18next' +import { Card } from '@/components/ui/Card' +import type { AddressString } from '@/lib/schemas' +import { useAgentCard } from '@/services/agent-nft/hooks' +import { type AgentRegistration, getAgentCardEndpoint } from '@/services/agent-nft/schemas' +import type { Erc721 } from '@/services/thor/tokens/erc721' +import { useAgentInfo } from '@/services/thor/tokens/agent-registry' +import { useAgentReputation } from '@/services/thor/tokens/reputation-registry' +import { NftDetailHeader } from '../NftDetailHeader' +import { NftTransfersSection } from '../NftTransfersSection' +import { OverviewTab } from './tabs/OverviewTab' +import { ServicesTab } from './tabs/ServicesTab' +import { StatisticsTab } from './tabs/StatisticsTab' +import { QualityTab } from './tabs/QualityTab' +import { FeedbackTab } from './tabs/FeedbackTab' +import { MetadataTab } from './tabs/MetadataTab' + +interface AgentNftViewProps { + contractAddress: AddressString + tokenId: bigint + collection: Erc721 + registration: AgentRegistration + nftImage: string + tokenUri: string | undefined +} + +export const AgentNftView = ({ + contractAddress, + tokenId, + collection, + registration, + nftImage, + tokenUri, +}: AgentNftViewProps) => { + const { t } = useTranslation() + + const nftName = registration.name || collection.name || `#${tokenId.toString()}` + // The agent NFT contract is itself the ERC-8004 AgentRegistry (tokenId == agentId). + const { data: agentInfo, isPending: isAgentInfoPending } = useAgentInfo({ contractAddress, agentId: tokenId }) + + const reputationAddress = registration.reputationRegistry?.address ?? null + const { data: reputation, isPending: isReputationPending } = useAgentReputation({ + reputationAddress, + agentId: tokenId, + }) + const hasReputationRegistry = !!reputationAddress + + const agentCardEndpoint = getAgentCardEndpoint(registration) + const { data: agentCard, isPending: isAgentCardPending } = useAgentCard({ endpoint: agentCardEndpoint }) + + return ( + + + + {t('AI Agent')} + + {t('Agent')} + + + + + + + + + {t('Overview')} + {t('Services')} + {t('Statistics')} + {t('Quality')} + {t('Feedback')} + {t('Metadata')} + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/FeedbackTab.tsx b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/FeedbackTab.tsx new file mode 100644 index 00000000..e2d8c894 --- /dev/null +++ b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/FeedbackTab.tsx @@ -0,0 +1,80 @@ +'use client' + +import { Badge, Skeleton, Text } from '@chakra-ui/react' +import { useTranslation } from 'react-i18next' +import { CopyableAddressLink } from '@/components/ui/Links' +import { type Column, DataTable, type TableRow } from '@/components/ui/Table' +import type { AddressString } from '@/lib/schemas' +import type { AgentReputation } from '@/services/thor/tokens/reputation-registry' +import { AgentEmptyState } from '../AgentDetail' + +interface FeedbackTabProps { + reputation: AgentReputation | undefined + isPending: boolean + hasReputationRegistry: boolean +} + +interface FeedbackRow extends TableRow { + id: string + client: string + value: string + status: string +} + +export const FeedbackTab = ({ reputation, isPending, hasReputationRegistry }: FeedbackTabProps) => { + const { t } = useTranslation() + + if (!hasReputationRegistry) { + return ( + + ) + } + + if (isPending) { + return + } + + if (!reputation || reputation.feedback.length === 0) { + return ( + + ) + } + + const columns: Column[] = [ + { + key: 'client', + label: t('Client'), + Cell: ({ value }) => , + }, + { + key: 'value', + label: t('Rating'), + Cell: ({ value }) => ( + + {String(value)} + + ), + }, + { + key: 'status', + label: t('Status'), + Cell: ({ value }) => ( + + {value === 'revoked' ? t('Revoked') : t('Active')} + + ), + }, + ] + + const rows: FeedbackRow[] = reputation.feedback.map(entry => ({ + id: `${entry.client}-${entry.index}`, + client: entry.client, + value: String(entry.value), + status: entry.revoked ? 'revoked' : 'active', + })) + + return +} diff --git a/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/MetadataTab.tsx b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/MetadataTab.tsx new file mode 100644 index 00000000..45522e4c --- /dev/null +++ b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/MetadataTab.tsx @@ -0,0 +1,60 @@ +'use client' + +import { Box, Stack, Text } from '@chakra-ui/react' +import { useTranslation } from 'react-i18next' +import { CopyableAddressLink } from '@/components/ui/Links' +import type { AddressString } from '@/lib/schemas' +import { type AgentRegistration, parseCaipAddress } from '@/services/agent-nft/schemas' +import { DetailRow, SectionCard } from '../AgentDetail' + +interface MetadataTabProps { + registration: AgentRegistration + contractAddress: AddressString + tokenId: bigint + tokenUri: string | undefined +} + +export const MetadataTab = ({ registration, contractAddress, tokenId, tokenUri }: MetadataTabProps) => { + const { t } = useTranslation() + const reputationAddress = registration.reputationRegistry?.address + // Prefer the registry from the metadata's CAIP-10 reference; fall back to the NFT contract. + const registryAddress = parseCaipAddress(registration.registrations[0]?.agentRegistry) ?? contractAddress + + return ( + + + + + #{tokenId.toString()} + + + + + + {reputationAddress && ( + + + + )} + + + {registration.type} + + + + + + + {tokenUri && ( + + {tokenUri} + + )} + + {JSON.stringify(registration, null, 2)} + + + + + ) +} diff --git a/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/OverviewTab.tsx b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/OverviewTab.tsx new file mode 100644 index 00000000..ee9c528c --- /dev/null +++ b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/OverviewTab.tsx @@ -0,0 +1,80 @@ +'use client' + +import { Badge, Skeleton, Text } from '@chakra-ui/react' +import { useTranslation } from 'react-i18next' +import { CopyableAddressLink } from '@/components/ui/Links' +import { useFormatDate } from '@/hooks/useFormatting' +import type { AgentRegistration } from '@/services/agent-nft/schemas' +import type { AgentInfo } from '@/services/thor/tokens/agent-registry' +import { DetailRow, SectionCard } from '../AgentDetail' + +interface OverviewTabProps { + registration: AgentRegistration + agentInfo: AgentInfo | null | undefined + isAgentInfoPending: boolean +} + +export const OverviewTab = ({ registration, agentInfo, isAgentInfoPending }: OverviewTabProps) => { + const { t } = useTranslation() + const formatDate = useFormatDate() + + const agentId = registration.registrations[0]?.agentId + + return ( + + + + {registration.name || '-'} + + + {registration.description && ( + + + {registration.description} + + + )} + + + #{agentId ?? '-'} + + + + {isAgentInfoPending ? ( + + ) : agentInfo?.creator ? ( + + ) : ( + + - + + )} + + {agentInfo?.registeredAt ? ( + + + {formatDate(agentInfo.registeredAt)} + + + ) : null} + + {agentInfo?.deactivated ? ( + {t('Deactivated')} + ) : agentInfo?.suspended ? ( + {t('Suspended')} + ) : registration.active === false ? ( + {t('Inactive')} + ) : ( + {t('Active')} + )} + + {registration.supportedTrust.length > 0 && ( + + + {registration.supportedTrust.join(', ')} + + + )} + + ) +} diff --git a/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/QualityTab.tsx b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/QualityTab.tsx new file mode 100644 index 00000000..456ddad8 --- /dev/null +++ b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/QualityTab.tsx @@ -0,0 +1,57 @@ +'use client' + +import { Skeleton, Text } from '@chakra-ui/react' +import { useTranslation } from 'react-i18next' +import { useFormatNumber } from '@/hooks/useFormatting' +import type { AgentReputation } from '@/services/thor/tokens/reputation-registry' +import { AgentEmptyState, DetailRow, SectionCard } from '../AgentDetail' + +interface QualityTabProps { + reputation: AgentReputation | undefined + isPending: boolean + hasReputationRegistry: boolean +} + +export const QualityTab = ({ reputation, isPending, hasReputationRegistry }: QualityTabProps) => { + const { t } = useTranslation() + const formatNumber = useFormatNumber() + + if (!hasReputationRegistry) { + return ( + + ) + } + + if (isPending) { + return + } + + if (!reputation || reputation.feedbackCount === 0) { + return ( + + ) + } + + return ( + + + + {reputation.averageValue != null ? formatNumber(reputation.averageValue, { maximumFractionDigits: 2 }) : '-'} + + + + + {formatNumber(reputation.feedbackCount)} + + + + + {formatNumber(reputation.clientCount)} + + + + ) +} diff --git a/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/ServicesTab.tsx b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/ServicesTab.tsx new file mode 100644 index 00000000..11f8bca9 --- /dev/null +++ b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/ServicesTab.tsx @@ -0,0 +1,128 @@ +'use client' + +import { Badge, Box, Link, Skeleton, Stack, Text, Wrap } from '@chakra-ui/react' +import { useTranslation } from 'react-i18next' +import { LuExternalLink } from 'react-icons/lu' +import type { AgentCard, AgentRegistration } from '@/services/agent-nft/schemas' +import { AgentEmptyState, DetailRow, SectionCard } from '../AgentDetail' + +interface ServicesTabProps { + registration: AgentRegistration + agentCard: AgentCard | null | undefined + isAgentCardPending: boolean +} + +const EndpointLink = ({ href }: { href: string }) => ( + + + {href} + + + +) + +export const ServicesTab = ({ registration, agentCard, isAgentCardPending }: ServicesTabProps) => { + const { t } = useTranslation() + const { services } = registration + const hasServices = services.length > 0 + + if (!hasServices && !isAgentCardPending && !agentCard) { + return ( + + ) + } + + return ( + + {hasServices && ( + + {services.map((service, index) => ( + + + {service.endpoint ? ( + + ) : ( + + - + + )} + {service.version && ( + + {`v${service.version}`} + + )} + + + ))} + + )} + + {isAgentCardPending ? ( + + ) : agentCard ? ( + + + + {agentCard.version || '-'} + + + + + {agentCard.capabilities.streaming ? t('Enabled') : t('Disabled')} + + + {agentCard.defaultInputModes.length > 0 && ( + + + {agentCard.defaultInputModes.join(', ')} + + + )} + {agentCard.defaultOutputModes.length > 0 && ( + + + {agentCard.defaultOutputModes.join(', ')} + + + )} + {agentCard.url && ( + + + + )} + + ) : null} + + {agentCard && agentCard.skills.length > 0 && ( + + {agentCard.skills.map((skill, index) => ( + + {skill.description ? ( + + {skill.description} + + ) : ( + + + {skill.id} + + + )} + + ))} + + )} + + ) +} diff --git a/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/StatisticsTab.tsx b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/StatisticsTab.tsx new file mode 100644 index 00000000..debc4915 --- /dev/null +++ b/app/[locale]/nft/[contractAddress]/[tokenId]/components/agent/tabs/StatisticsTab.tsx @@ -0,0 +1,58 @@ +'use client' + +import { Skeleton, Text } from '@chakra-ui/react' +import { useTranslation } from 'react-i18next' +import { LuMessageSquare, LuUsers } from 'react-icons/lu' +import { DataCardGroup } from '@/components/ui/DataCardGroup' +import { useFormatNumber } from '@/hooks/useFormatting' +import type { AgentReputation } from '@/services/thor/tokens/reputation-registry' +import { AgentEmptyState } from '../AgentDetail' + +interface StatisticsTabProps { + reputation: AgentReputation | undefined + isPending: boolean + hasReputationRegistry: boolean +} + +export const StatisticsTab = ({ reputation, isPending, hasReputationRegistry }: StatisticsTabProps) => { + const { t } = useTranslation() + const formatNumber = useFormatNumber() + + if (!hasReputationRegistry) { + return ( + + ) + } + + if (isPending) { + return + } + + return ( + , + title: t('Total Feedback'), + children: ( + + {formatNumber(reputation?.feedbackCount ?? 0)} + + ), + }, + { + icon: , + title: t('Unique Clients'), + children: ( + + {formatNumber(reputation?.clientCount ?? 0)} + + ), + }, + ]} + /> + ) +} diff --git a/i18n/languages/de.json b/i18n/languages/de.json index d1c49f0a..38acddba 100644 --- a/i18n/languages/de.json +++ b/i18n/languages/de.json @@ -2,6 +2,7 @@ "1D": "1T", "1M": "1M", "1Y": "1J", + "A2A Agent Card": "A2A-Agentenkarte", "Account": "Konto", "Active": "Aktiv", "Active Stake": "Active Stake", @@ -11,12 +12,18 @@ "AFPT": "AFPT", "AFPU": "AFPU", "Age": "Alter", + "Agent": "Agent", + "Agent ID": "Agent-ID", + "Agent Overview": "Agentenübersicht", + "Agent Registry": "Agenten-Registry", + "AI Agent": "KI-Agent", "All": "Alle", "All Time": "Gesamte Zeit", "Amount": "Betrag", "Attributes": "Attribute", "Average Fees Per Transaction (AFPT)": "Average Fees Per Transaction (AFPT)", "Average Fees Per User (AFPU)": "Durchschnittliche Gebühren pro Benutzer (AFPU)", + "Average Rating": "Durchschnittliche Bewertung", "Avg AFPT": "Avg AFPT", "Avg AFPU": "Durchschn. AFPU", "Avg Gas Limit/Block": "Durchschn. Gaslimit/Block", @@ -54,6 +61,7 @@ "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.": "Klausel #{{index}} mit dem Selector {{selector}} wurde sofort ohne decodierten Grund reverted. Das bedeutet oft, dass die Calldata mit einer veralteten ABI oder einer falschen Funktionssignatur kodiert wurde.", "Clause details": "Klauseldetails", "Clauses": "Klauseln", + "Client": "Client", "Close navigation menu": "Close navigation menu", "Co2e": "CO₂e", "CO2e emitted": "Ausgestoßenes CO2e", @@ -73,6 +81,7 @@ "Created contract address": "Erstellte Vertragsadresse", "Created On": "Erstellt am", "Creation Transaction": "Erstellungstransaktion", + "Creator": "Ersteller", "Cycle duration": "Zyklusdauer", "Cycle left": "Verbleibende Zyklen", "Daily": "Täglich", @@ -81,6 +90,7 @@ "Date": "Datum", "Date & Time": "Datum & Uhrzeit", "Date time": "Datum Uhrzeit", + "Deactivated": "Deaktiviert", "Decode": "Dekodieren", "Decoded": "Entschlüsselt", "decoded": "decodiert", @@ -96,10 +106,13 @@ "details": "Details", "Dev mode": "Dev-Modus", "DEX Trades": "DEX Trades", + "Disabled": "Deaktiviert", "Earned Rewards": "Verdiente Belohnungen", "emitter": "Sender", + "Enabled": "Aktiviert", "Endorsed validators": "Befürwortete Validatoren", "Endorser": "Befürworter", + "Endpoint": "Endpunkt", "Enter a valid URL": "Gib eine gültige URL ein", "Events": "Ereignisse", "events": "Ereignisse", @@ -111,6 +124,7 @@ "Fee": "Gebühr", "Fee delegated to": "Gebühr delegiert an", "Fee Paid": "Gezahlte Gebühr", + "Feedback": "Feedback", "Fees, Gas and VTHO": "Gebühren, Gas und VTHO", "Finalized": "Abgeschlossen", "Finalizing": "Wird abgeschlossen", @@ -136,6 +150,7 @@ "indexed": "indiziert", "Indexer URL must not include /api or /v": "Die Indexer-URL darf weder /api noch /v enthalten", "Input data": "Eingabedaten", + "Input Modes": "Eingabemodi", "input-data": "Eingabedaten", "Inspect tool": "Inspektionswerkzeug", "Last page": "Letzte Seite", @@ -145,6 +160,7 @@ "Market Cap": "Marktkapitalisierung", "Marketplace": "Marktplatz", "Max Fee per Gas": "Max. Gebühr pro Gas", + "Metadata": "Metadaten", "Metadata not found at this uri": "Metadaten unter dieser URI nicht gefunden", "Metrics": "Metriken", "Mint": "Prägen", @@ -171,8 +187,13 @@ "No contract creation": "Kein Vertragsabschluss", "No contracts": "Keine Verträge", "No events": "Keine Ereignisse", + "No feedback available": "Kein Feedback verfügbar", + "No feedback yet": "Noch kein Feedback", "No image": "Kein Bild", "No NFTs": "Keine NFTs", + "No quality data available": "Keine Qualitätsdaten verfügbar", + "No services listed": "Keine Dienste aufgeführt", + "No statistics available": "Keine Statistiken verfügbar", "No token transfers": "Keine Token-Übertragungen", "No token transfers have been recorded yet": "Es wurden noch keine Token-Übertragungen aufgezeichnet", "No tokens": "Keine Token", @@ -183,9 +204,12 @@ "Not delegated": "Nicht delegiert", "Now": "Jetzt", "of": "von", + "On-chain Identity": "On-Chain-Identität", "Oops! Something went wrong": "Ups! Etwas ist schiefgelaufen.", "Open navigation menu": "Open navigation menu", "Origin": "Herkunft", + "Output Modes": "Ausgabemodi", + "Overview": "Übersicht", "Owned by": "Im Besitz von", "Owned Contracts": "Eigene Verträge", "Page": "Seite", @@ -199,37 +223,50 @@ "Price": "Preis", "Priority Fee per Gas": "Prioritätsgebühr pro Gas", "Privacy Policy": "Datenschutzerklärung", + "Quality": "Qualität", + "Rating": "Bewertung", "Raw": "Roh", "raw": "Rohdaten", + "Raw Metadata": "Rohe Metadaten", + "Registered": "Registriert", "Reliability": "Zuverlässigkeit", + "Reputation Registry": "Reputations-Registry", "Reset": "Zurücksetzen", "Resources": "Ressourcen", "Revert Reason": "Rückgabegrund", "Reverted": "Zurückgesetzt", + "Revoked": "Widerrufen", "Rewards": "Belohnungen", "Rows": "Zeilen", "Rows per page": "Zeilen pro Seite", "Sale": "Verkauf", "Save": "Speichern", + "Schema": "Schema", "Search": "Search", "Search for blocks, transactions or accounts": "Suche nach Blöcken, Transaktionen oder Konten", "Select Currency": "Währung auswählen", "Select Language": "Sprache auswählen", + "Services": "Dienste", "Show": "Anzeigen", "Show All": "Alle anzeigen", "Show Less": "Weniger anzeigen", "Signer": "Unterzeichner", "Size": "Größe", + "Skills": "Fähigkeiten", "Solo indexer URL": "Solo-Indexer-URL", "Solo node URL": "Solo-Node-URL", "Something went wrong 😬": "Etwas ist schiefgelaufen 😬", "Staking NFTs": "Staking-NFTs", "Stargate": "Stargate", "StarGate Docs": "StarGate-Dokumentation", + "Statistics": "Statistiken", "Status": "Status", + "Streaming": "Streaming", "success": "Erfolg", "Support": "Support", "Support Center": "Support-Center", + "Supported Trust": "Unterstützte Vertrauensmodelle", + "Suspended": "Ausgesetzt", "Symbol": "Symbol", "Terms of Service": "Nutzungsbedingungen", "Testnet": "Testnet", @@ -242,6 +279,9 @@ "This account has not deployed any contracts yet": "Dieses Konto hat noch keine Verträge bereitgestellt", "This account has not made any transactions yet": "Dieses Konto hat noch keine Transaktionen durchgeführt", "This account has not made any transfers yet": "Dieses Konto hat noch keine Überweisungen durchgeführt", + "This agent does not publish an on-chain reputation registry": "Dieser Agent veröffentlicht kein On-Chain-Reputationsregister", + "This agent has not advertised any services yet": "Dieser Agent hat noch keine Dienste angegeben", + "This agent has not received any feedback yet": "Dieser Agent hat noch kein Feedback erhalten", "This clause has no contract creation": "Diese Klausel hat keine Vertragserstellung", "This page does not exist": "Diese Seite existiert nicht", "This transaction has no events": "Diese Transaktion hat keine Ereignisse", @@ -261,6 +301,7 @@ "Total Clauses": "Gesamte Klauseln", "Total Earned": "Insgesamt verdient", "Total EUR": "Gesamt EUR", + "Total Feedback": "Feedback gesamt", "Total Fees Paid": "Gezahlte Gesamtgebühren", "Total Gas Used": "Insgesamt verbrauchtes Gas", "Total Holders": "Gesamte Inhaber", @@ -288,6 +329,7 @@ "Tx ID": "Transaktions-ID", "Txs/Clauses": "Txs/Klauseln", "Type": "Typ", + "Unique Clients": "Eindeutige Clients", "Unknown": "Unbekannt", "Usage": "Nutzung", "USD": "USD", @@ -300,6 +342,7 @@ "Validators": "Validatoren", "Value": "Wert", "VeChain": "VeChain", + "Version": "Version", "VET": "VET", "VET Balance": "VET-Bestand", "VET Price": "VET-Preis", diff --git a/i18n/languages/el.json b/i18n/languages/el.json index 32ad2a47..faa87421 100644 --- a/i18n/languages/el.json +++ b/i18n/languages/el.json @@ -2,6 +2,7 @@ "1D": "1Η", "1M": "1Μ", "1Y": "1Χ", + "A2A Agent Card": "Κάρτα πράκτορα A2A", "Account": "Λογαριασμός", "Active": "Ενεργό", "Active Stake": "Active Stake", @@ -11,12 +12,18 @@ "AFPT": "AFPT", "AFPU": "AFPU", "Age": "Ηλικία", + "Agent": "Πράκτορας", + "Agent ID": "Αναγνωριστικό πράκτορα", + "Agent Overview": "Επισκόπηση πράκτορα", + "Agent Registry": "Μητρώο πρακτόρων", + "AI Agent": "Πράκτορας AI", "All": "Όλα", "All Time": "Συνολικά", "Amount": "Ποσό", "Attributes": "Χαρακτηριστικά", "Average Fees Per Transaction (AFPT)": "Average Fees Per Transaction (AFPT)", "Average Fees Per User (AFPU)": "Μέσα Τέλη ανά Χρήστη (AFPU)", + "Average Rating": "Μέση βαθμολογία", "Avg AFPT": "Avg AFPT", "Avg AFPU": "Μέσο AFPU", "Avg Gas Limit/Block": "Μέσο Όριο Gas/Μπλοκ", @@ -54,6 +61,7 @@ "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.": "Η ρήτρα #{{index}} με selector {{selector}} έκανε revert αμέσως χωρίς αποκωδικοποιημένο λόγο. Αυτό συχνά σημαίνει ότι το calldata κωδικοποιήθηκε με παλιό ABI ή με λάθος υπογραφή συνάρτησης.", "Clause details": "Λεπτομέρειες Ρήτρας", "Clauses": "Ρήτρες", + "Client": "Πελάτης", "Close navigation menu": "Close navigation menu", "Co2e": "Co2e", "CO2e emitted": "Εκπεμπόμενο CO2e", @@ -73,6 +81,7 @@ "Created contract address": "Διεύθυνση δημιουργημένου συμβολαίου", "Created On": "Ημερομηνία Δημιουργίας", "Creation Transaction": "Συναλλαγή δημιουργίας", + "Creator": "Δημιουργός", "Cycle duration": "Διάρκεια κύκλου", "Cycle left": "Υπόλοιπο κύκλου", "Daily": "Ημερήσια", @@ -81,6 +90,7 @@ "Date": "Ημερομηνία", "Date & Time": "Ημερομηνία & Ώρα", "Date time": "Ημερομηνία και ώρα", + "Deactivated": "Απενεργοποιημένο", "Decode": "Αποκωδικοποίηση", "Decoded": "Αποκωδικοποιημένο", "decoded": "αποκωδικοποιημένο", @@ -96,10 +106,13 @@ "details": "λεπτομέρειες", "Dev mode": "Λειτουργία ανάπτυξης", "DEX Trades": "DEX Trades", + "Disabled": "Ανενεργό", "Earned Rewards": "Κερδισμένες ανταμοιβές", "emitter": "εκδότης", + "Enabled": "Ενεργό", "Endorsed validators": "Υποστηριζόμενοι validators", "Endorser": "Εντολέας", + "Endpoint": "Σημείο πρόσβασης", "Enter a valid URL": "Εισαγάγετε ένα έγκυρο URL", "Events": "Γεγονότα", "events": "γεγονότα", @@ -111,6 +124,7 @@ "Fee": "Τέλος", "Fee delegated to": "Τέλος εκχωρήθηκε σε", "Fee Paid": "Πληρωθείσα Προμήθεια", + "Feedback": "Σχόλια", "Fees, Gas and VTHO": "Τέλη, Gas και VTHO", "Finalized": "Ολοκληρώθηκε", "Finalizing": "Ολοκλήρωση", @@ -136,6 +150,7 @@ "indexed": "ευρετηριασμένο", "Indexer URL must not include /api or /v": "Το URL του indexer δεν πρέπει να περιλαμβάνει /api ή /v", "Input data": "Δεδομένα εισόδου", + "Input Modes": "Λειτουργίες εισόδου", "input-data": "δεδομένα εισόδου", "Inspect tool": "Εργαλείο επιθεώρησης", "Last page": "Τελευταία σελίδα", @@ -145,6 +160,7 @@ "Market Cap": "Κεφαλαιοποίηση Αγοράς", "Marketplace": "Αγορά", "Max Fee per Gas": "Μέγιστο τέλος ανά Gas", + "Metadata": "Μεταδεδομένα", "Metadata not found at this uri": "Τα μεταδεδομένα δεν βρέθηκαν σε αυτό το URI", "Metrics": "Μετρήσεις", "Mint": "Κόπηση", @@ -171,8 +187,13 @@ "No contract creation": "Δεν δημιουργήθηκε συμβόλαιο", "No contracts": "Καμία σύμβαση", "No events": "Δεν υπάρχουν γεγονότα", + "No feedback available": "Δεν υπάρχουν διαθέσιμα σχόλια", + "No feedback yet": "Δεν υπάρχουν σχόλια ακόμη", "No image": "Δεν υπάρχει εικόνα", "No NFTs": "Δεν υπάρχουν NFT", + "No quality data available": "Δεν υπάρχουν δεδομένα ποιότητας", + "No services listed": "Δεν υπάρχουν υπηρεσίες", + "No statistics available": "Δεν υπάρχουν στατιστικά", "No token transfers": "Δεν υπάρχουν μεταφορές token", "No token transfers have been recorded yet": "Δεν έχουν καταγραφεί μεταφορές token ακόμα", "No tokens": "Δεν υπάρχουν tokens", @@ -183,9 +204,12 @@ "Not delegated": "Δεν έχει γίνει ανάθεση", "Now": "Τώρα", "of": "από", + "On-chain Identity": "Ταυτότητα on-chain", "Oops! Something went wrong": "Κάτι πήγε στραβά", "Open navigation menu": "Open navigation menu", "Origin": "Προέλευση", + "Output Modes": "Λειτουργίες εξόδου", + "Overview": "Επισκόπηση", "Owned by": "Ανήκει σε", "Owned Contracts": "Συμβόλαια σε Κατοχή", "Page": "Σελίδα", @@ -199,37 +223,50 @@ "Price": "Τιμή", "Priority Fee per Gas": "Τέλος προτεραιότητας ανά Gas", "Privacy Policy": "Πολιτική Απορρήτου", + "Quality": "Ποιότητα", + "Rating": "Βαθμολογία", "Raw": "Ακατέργαστο", "raw": "ακατέργαστο", + "Raw Metadata": "Ακατέργαστα μεταδεδομένα", + "Registered": "Καταχωρήθηκε", "Reliability": "Αξιοπιστία", + "Reputation Registry": "Μητρώο φήμης", "Reset": "Επαναφορά", "Resources": "Πόροι", "Revert Reason": "Λόγος Επαναφοράς", "Reverted": "Αναστράφηκε", + "Revoked": "Ανακλήθηκε", "Rewards": "Ανταμοιβές", "Rows": "Γραμμές", "Rows per page": "Γραμμές ανά σελίδα", "Sale": "Πώληση", "Save": "Αποθήκευση", + "Schema": "Σχήμα", "Search": "Search", "Search for blocks, transactions or accounts": "Αναζήτηση για blocks, συναλλαγές ή λογαριασμούς", "Select Currency": "Επιλέξτε Νόμισμα", "Select Language": "Επιλογή γλώσσας", + "Services": "Υπηρεσίες", "Show": "Εμφάνιση", "Show All": "Εμφάνιση όλων", "Show Less": "Εμφάνιση λιγότερων", "Signer": "Υπογράφων", "Size": "Μέγεθος", + "Skills": "Δεξιότητες", "Solo indexer URL": "URL indexer Solo", "Solo node URL": "URL node Solo", "Something went wrong 😬": "Κάτι πήγε στραβά 😬", "Staking NFTs": "Staking NFTs", "Stargate": "Stargate", "StarGate Docs": "Έγγραφα StarGate", + "Statistics": "Στατιστικά", "Status": "Κατάσταση", + "Streaming": "Ροή", "success": "επιτυχία", "Support": "Υποστήριξη", "Support Center": "Κέντρο Υποστήριξης", + "Supported Trust": "Υποστηριζόμενη εμπιστοσύνη", + "Suspended": "Σε αναστολή", "Symbol": "Σύμβολο", "Terms of Service": "Όροι Χρήσης", "Testnet": "Testnet", @@ -242,6 +279,9 @@ "This account has not deployed any contracts yet": "Αυτός ο λογαριασμός δεν έχει αναπτύξει καμία σύμβαση ακόμη", "This account has not made any transactions yet": "Αυτός ο λογαριασμός δεν έχει πραγματοποιήσει καμία συναλλαγή ακόμα", "This account has not made any transfers yet": "Αυτός ο λογαριασμός δεν έχει πραγματοποιήσει καμία μεταφορά ακόμα", + "This agent does not publish an on-chain reputation registry": "Αυτός ο πράκτορας δεν δημοσιεύει μητρώο φήμης on-chain", + "This agent has not advertised any services yet": "Αυτός ο πράκτορας δεν έχει δηλώσει ακόμη υπηρεσίες", + "This agent has not received any feedback yet": "Αυτός ο πράκτορας δεν έχει λάβει σχόλια ακόμη", "This clause has no contract creation": "Αυτή η ενότητα δεν έχει δημιουργία συμβολαίου", "This page does not exist": "Αυτή η σελίδα δεν υπάρχει", "This transaction has no events": "Αυτή η συναλλαγή δεν έχει γεγονότα", @@ -261,6 +301,7 @@ "Total Clauses": "Συνολικές Ρήτρες", "Total Earned": "Συνολικά Κέρδη", "Total EUR": "Σύνολο EUR", + "Total Feedback": "Σύνολο σχολίων", "Total Fees Paid": "Συνολικά Τέλη που Καταβλήθηκαν", "Total Gas Used": "Συνολικό Gas που χρησιμοποιήθηκε", "Total Holders": "Συνολικοί Κατόχοι", @@ -288,6 +329,7 @@ "Tx ID": "Ταυτότητα Συναλλαγής", "Txs/Clauses": "Συναλλαγές/Ρήτρες", "Type": "Τύπος", + "Unique Clients": "Μοναδικοί πελάτες", "Unknown": "Άγνωστο", "Usage": "Χρήση", "USD": "USD", @@ -300,6 +342,7 @@ "Validators": "Επικυρωτές", "Value": "Τιμή", "VeChain": "VeChain", + "Version": "Έκδοση", "VET": "VET", "VET Balance": "Υπόλοιπο VET", "VET Price": "Τιμή VET", diff --git a/i18n/languages/en.json b/i18n/languages/en.json index 333552c8..d89daaf6 100644 --- a/i18n/languages/en.json +++ b/i18n/languages/en.json @@ -3,6 +3,7 @@ "1D": "1D", "1M": "1M", "1Y": "1Y", + "A2A Agent Card": "A2A Agent Card", "Account": "Account", "Active": "Active", "Active Stake": "Active Stake", @@ -12,6 +13,11 @@ "AFPT": "AFPT", "AFPU": "AFPU", "Age": "Age", + "Agent": "Agent", + "Agent ID": "Agent ID", + "Agent Overview": "Agent Overview", + "Agent Registry": "Agent Registry", + "AI Agent": "AI Agent", "All": "All", "All Time": "All Time", "Amount": "Amount", @@ -19,6 +25,7 @@ "Attributes": "Attributes", "Average Fees Per Transaction (AFPT)": "Average Fees Per Transaction (AFPT)", "Average Fees Per User (AFPU)": "Average Fees Per User (AFPU)", + "Average Rating": "Average Rating", "Avg AFPT": "Avg AFPT", "Avg AFPU": "Avg AFPU", "Avg Gas Limit/Block": "Avg Gas Limit/Block", @@ -58,6 +65,7 @@ "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.": "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.", "Clause details": "Clause details", "Clauses": "Clauses", + "Client": "Client", "Close": "Close", "Close navigation menu": "Close navigation menu", "Co2e": "Co2e", @@ -67,18 +75,20 @@ "Coming soon": "Coming soon", "Configure Solo endpoints": "Configure Solo endpoints", "Confirmations": "Confirmations", - "contract creation": "contract creation", "Contract": "Contract", "Contract Address": "Contract Address", "Contract created": "Contract created", + "contract creation": "contract creation", "Contract creation": "Contract creation", "Contract Details": "Contract Details", "Contract Master": "Contract Master", "Cookie Policy": "Cookie Policy", "Copy to clipboard": "Copy to clipboard", + "Create": "Create", "Created contract address": "Created contract address", "Created On": "Created On", "Creation Transaction": "Creation Transaction", + "Creator": "Creator", "Cycle duration": "Cycle duration", "Cycle left": "Cycle left", "Daily": "Daily", @@ -87,7 +97,7 @@ "Date": "Date", "Date & Time": "Date & Time", "Date time": "Date time", - "Create": "Create", + "Deactivated": "Deactivated", "Decode": "Decode", "Decoded": "Decoded", "decoded": "decoded", @@ -103,13 +113,16 @@ "details": "details", "Dev mode": "Dev mode", "DEX Trades": "DEX Trades", + "Disabled": "Disabled", "Download Again": "Download Again", "Earned Rewards": "Earned Rewards", "emitted by": "emitted by", "emitter": "emitter", + "Enabled": "Enabled", "End Date": "End Date", "Endorsed validators": "Endorsed validators", "Endorser": "Endorser", + "Endpoint": "Endpoint", "Enter a valid URL": "Enter a valid URL", "ERC-20": "ERC-20", "ERC-721": "ERC-721", @@ -128,6 +141,7 @@ "Fee": "Fee", "Fee delegated to": "Fee delegated to", "Fee Paid": "Fee Paid", + "Feedback": "Feedback", "Fees, Gas and VTHO": "Fees, Gas and VTHO", "Fetching transfers...": "Fetching transfers...", "Finalized": "Finalized", @@ -155,6 +169,7 @@ "indexed": "indexed", "Indexer URL must not include /api or /v": "Indexer URL must not include /api or /v", "Input data": "Input data", + "Input Modes": "Input Modes", "input-data": "input-data", "Inspect tool": "Inspect tool", "Last page": "Last page", @@ -164,11 +179,13 @@ "Market Cap": "Market Cap", "Marketplace": "Marketplace", "Max Fee per Gas": "Max Fee per Gas", + "Metadata": "Metadata", "Metadata not found at this uri": "Metadata not found at this uri", "Metrics": "Metrics", "Mint": "Mint", "Minted by": "Minted by", "Minted on": "Minted on", + "mode": "mode", "Monthly": "Monthly", "Multi-token": "Multi-token", "Name": "Name", @@ -191,12 +208,16 @@ "No contracts": "No contracts", "No events": "No events", "No events — this transaction emitted no logs.": "No events — this transaction emitted no logs.", - "No parameters.": "No parameters.", + "No feedback available": "No feedback available", + "No feedback yet": "No feedback yet", "No image": "No image", "No NFTs": "No NFTs", + "No parameters.": "No parameters.", + "No quality data available": "No quality data available", + "No services listed": "No services listed", + "No statistics available": "No statistics available", "No token transfers": "No token transfers", "No token transfers have been recorded yet": "No token transfers have been recorded yet", - "mode": "mode", "No tokens": "No tokens", "No transactions": "No transactions", "No transactions have been recorded yet": "No transactions have been recorded yet", @@ -206,9 +227,12 @@ "Not delegated": "Not delegated", "Now": "Now", "of": "of", + "On-chain Identity": "On-chain Identity", "Oops! Something went wrong": "Oops! Something went wrong", "Open navigation menu": "Open navigation menu", "Origin": "Origin", + "Output Modes": "Output Modes", + "Overview": "Overview", "Owned by": "Owned by", "Owned Contracts": "Owned Contracts", "Page": "Page", @@ -216,34 +240,43 @@ "Paid fee": "Paid fee", "Parent block": "Parent block", "Passive generation": "Passive generation", - "Plain VET transfer — no contract call data.": "Plain VET transfer — no contract call data.", "Pending": "Pending", + "Plain VET transfer — no contract call data.": "Plain VET transfer — no contract call data.", "Possible selector mismatch": "Possible selector mismatch", "Previous page": "Previous page", "Price": "Price", "Priority Fee per Gas": "Priority Fee per Gas", "Privacy Policy": "Privacy Policy", + "Quality": "Quality", + "Rating": "Rating", "Raw": "Raw", "raw": "raw", + "Raw Metadata": "Raw Metadata", + "Registered": "Registered", "Reliability": "Reliability", + "Reputation Registry": "Reputation Registry", "Reset": "Reset", "Resources": "Resources", "Revert Reason": "Revert Reason", "Reverted": "Reverted", + "Revoked": "Revoked", "Rewards": "Rewards", "Rows": "Rows", "Rows per page": "Rows per page", "Sale": "Sale", "Save": "Save", + "Schema": "Schema", "Search": "Search", "Search for blocks, transactions or accounts": "Search for blocks, transactions or accounts", "Select Currency": "Select Currency", "Select Language": "Select Language", + "Services": "Services", "Show": "Show", "Show All": "Show All", "Show Less": "Show Less", "Signer": "Signer", "Size": "Size", + "Skills": "Skills", "Solo indexer URL": "Solo indexer URL", "Solo node URL": "Solo node URL", "Something went wrong 😬": "Something went wrong 😬", @@ -251,11 +284,15 @@ "Stargate": "Stargate", "StarGate Docs": "StarGate Docs", "Start Date": "Start Date", + "Statistics": "Statistics", "Stats": "Stats", "Status": "Status", + "Streaming": "Streaming", "success": "success", "Support": "Support", "Support Center": "Support Center", + "Supported Trust": "Supported Trust", + "Suspended": "Suspended", "Symbol": "Symbol", "Terms of Service": "Terms of Service", "Testnet": "Testnet", @@ -268,6 +305,9 @@ "This account has not deployed any contracts yet": "This account has not deployed any contracts yet", "This account has not made any transactions yet": "This account has not made any transactions yet", "This account has not made any transfers yet": "This account has not made any transfers yet", + "This agent does not publish an on-chain reputation registry": "This agent does not publish an on-chain reputation registry", + "This agent has not advertised any services yet": "This agent has not advertised any services yet", + "This agent has not received any feedback yet": "This agent has not received any feedback yet", "This clause has no contract creation": "This clause has no contract creation", "This page does not exist": "This page does not exist", "This transaction has no events": "This transaction has no events", @@ -287,6 +327,7 @@ "Total Clauses": "Total Clauses", "Total Earned": "Total Earned", "Total EUR": "Total EUR", + "Total Feedback": "Total Feedback", "Total Fees Paid": "Total Fees Paid", "Total Gas Limit": "Total Gas Limit", "Total Gas Used": "Total Gas Used", @@ -316,6 +357,7 @@ "Tx ID": "Tx ID", "Txs/Clauses": "Txs/Clauses", "Type": "Type", + "Unique Clients": "Unique Clients", "Unknown": "Unknown", "Unknown event": "Unknown event", "Usage": "Usage", @@ -330,6 +372,7 @@ "Value": "Value", "Value transferred": "Value transferred", "VeChain": "VeChain", + "Version": "Version", "VET": "VET", "VET Balance": "VET Balance", "VET Price": "VET Price", diff --git a/i18n/languages/es.json b/i18n/languages/es.json index c953b0f4..c5c13147 100644 --- a/i18n/languages/es.json +++ b/i18n/languages/es.json @@ -2,6 +2,7 @@ "1D": "1D", "1M": "1M", "1Y": "1A", + "A2A Agent Card": "Tarjeta de agente A2A", "Account": "Cuenta", "Active": "Activo", "Active Stake": "Active Stake", @@ -11,12 +12,18 @@ "AFPT": "AFPT", "AFPU": "AFPU", "Age": "Edad", + "Agent": "Agente", + "Agent ID": "ID del agente", + "Agent Overview": "Resumen del agente", + "Agent Registry": "Registro de agentes", + "AI Agent": "Agente de IA", "All": "Todo", "All Time": "Todo el tiempo", "Amount": "Cantidad", "Attributes": "Atributos", "Average Fees Per Transaction (AFPT)": "Average Fees Per Transaction (AFPT)", "Average Fees Per User (AFPU)": "Tarifas Promedio por Usuario (AFPU)", + "Average Rating": "Calificación media", "Avg AFPT": "Avg AFPT", "Avg AFPU": "AFPU Prom.", "Avg Gas Limit/Block": "Límite de gas promedio/Bloque", @@ -54,6 +61,7 @@ "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.": "La cláusula #{{index}} con el selector {{selector}} revirtió inmediatamente sin una razón decodificada. Esto suele significar que la calldata se codificó con una ABI desactualizada o una firma de función incorrecta.", "Clause details": "Detalles de la cláusula", "Clauses": "Cláusulas", + "Client": "Cliente", "Close navigation menu": "Close navigation menu", "Co2e": "Co2e", "CO2e emitted": "CO2e emitido", @@ -73,6 +81,7 @@ "Created contract address": "Dirección del contrato creado", "Created On": "Creado el", "Creation Transaction": "Transacción de creación", + "Creator": "Creador", "Cycle duration": "Duración del ciclo", "Cycle left": "Ciclo restante", "Daily": "Diario", @@ -81,6 +90,7 @@ "Date": "Fecha", "Date & Time": "Fecha y hora", "Date time": "Fecha y hora", + "Deactivated": "Desactivado", "Decode": "Decodificar", "Decoded": "Decodificado", "decoded": "decodificado", @@ -96,10 +106,13 @@ "details": "detalles", "Dev mode": "Modo dev", "DEX Trades": "DEX Trades", + "Disabled": "Deshabilitado", "Earned Rewards": "Recompensas obtenidas", "emitter": "emisor", + "Enabled": "Habilitado", "Endorsed validators": "Validadores avalados", "Endorser": "Avalista", + "Endpoint": "Endpoint", "Enter a valid URL": "Introduce una URL válida", "Events": "Eventos", "events": "eventos", @@ -111,6 +124,7 @@ "Fee": "Comisión", "Fee delegated to": "Comisión delegada a", "Fee Paid": "Tarifa pagada", + "Feedback": "Comentarios", "Fees, Gas and VTHO": "Comisiones, Gas y VTHO", "Finalized": "Finalizado", "Finalizing": "Finalizando", @@ -136,6 +150,7 @@ "indexed": "indexado", "Indexer URL must not include /api or /v": "La URL del indexador no debe incluir /api ni /v", "Input data": "Datos de entrada", + "Input Modes": "Modos de entrada", "input-data": "datos de entrada", "Inspect tool": "Herramienta de inspección", "Last page": "Última página", @@ -145,6 +160,7 @@ "Market Cap": "Capitalización de mercado", "Marketplace": "Mercado", "Max Fee per Gas": "Tarifa máxima por Gas", + "Metadata": "Metadatos", "Metadata not found at this uri": "Metadatos no encontrados en este URI", "Metrics": "Métricas", "Mint": "Mintear", @@ -171,8 +187,13 @@ "No contract creation": "Sin creación de contrato", "No contracts": "Sin contratos", "No events": "Sin eventos", + "No feedback available": "No hay comentarios disponibles", + "No feedback yet": "Aún no hay comentarios", "No image": "Sin imagen", "No NFTs": "Sin NFTs", + "No quality data available": "No hay datos de calidad disponibles", + "No services listed": "No hay servicios listados", + "No statistics available": "No hay estadísticas disponibles", "No token transfers": "Sin transferencias de tokens", "No token transfers have been recorded yet": "Aún no se han registrado transferencias de tokens", "No tokens": "Sin tokens", @@ -183,9 +204,12 @@ "Not delegated": "No delegado", "Now": "Ahora", "of": "de", + "On-chain Identity": "Identidad en la cadena", "Oops! Something went wrong": "¡Vaya! Algo salió mal", "Open navigation menu": "Open navigation menu", "Origin": "Origen", + "Output Modes": "Modos de salida", + "Overview": "Resumen", "Owned by": "Propietario", "Owned Contracts": "Contratos Poseídos", "Page": "Página", @@ -199,37 +223,50 @@ "Price": "Precio", "Priority Fee per Gas": "Tarifa de prioridad por Gas", "Privacy Policy": "Política de Privacidad", + "Quality": "Calidad", + "Rating": "Calificación", "Raw": "Crudo", "raw": "sin procesar", + "Raw Metadata": "Metadatos sin procesar", + "Registered": "Registrado", "Reliability": "Fiabilidad", + "Reputation Registry": "Registro de reputación", "Reset": "Restablecer", "Resources": "Recursos", "Revert Reason": "Razón de reversión", "Reverted": "Revertido", + "Revoked": "Revocado", "Rewards": "Recompensas", "Rows": "Filas", "Rows per page": "Filas por página", "Sale": "Venta", "Save": "Guardar", + "Schema": "Esquema", "Search": "Search", "Search for blocks, transactions or accounts": "Buscar bloques, transacciones o cuentas", "Select Currency": "Seleccionar moneda", "Select Language": "Seleccionar idioma", + "Services": "Servicios", "Show": "Mostrar", "Show All": "Mostrar todo", "Show Less": "Mostrar menos", "Signer": "Firmante", "Size": "Tamaño", + "Skills": "Habilidades", "Solo indexer URL": "URL del indexador de Solo", "Solo node URL": "URL del nodo de Solo", "Something went wrong 😬": "Algo salió mal 😬", "Staking NFTs": "Staking NFTs", "Stargate": "Stargate", "StarGate Docs": "Documentación de StarGate", + "Statistics": "Estadísticas", "Status": "Estado", + "Streaming": "Transmisión", "success": "éxito", "Support": "Soporte", "Support Center": "Centro de Soporte", + "Supported Trust": "Confianza admitida", + "Suspended": "Suspendido", "Symbol": "Símbolo", "Terms of Service": "Términos de Servicio", "Testnet": "Testnet", @@ -242,6 +279,9 @@ "This account has not deployed any contracts yet": "Esta cuenta aún no ha desplegado ningún contrato", "This account has not made any transactions yet": "Esta cuenta aún no ha realizado ninguna transacción", "This account has not made any transfers yet": "Esta cuenta aún no ha realizado ninguna transferencia", + "This agent does not publish an on-chain reputation registry": "Este agente no publica un registro de reputación en la cadena", + "This agent has not advertised any services yet": "Este agente aún no ha anunciado ningún servicio", + "This agent has not received any feedback yet": "Este agente aún no ha recibido comentarios", "This clause has no contract creation": "Esta cláusula no crea contrato", "This page does not exist": "Esta página no existe", "This transaction has no events": "Esta transacción no tiene eventos", @@ -261,6 +301,7 @@ "Total Clauses": "Cláusulas Totales", "Total Earned": "Total Ganado", "Total EUR": "Total EUR", + "Total Feedback": "Comentarios totales", "Total Fees Paid": "Tarifas Totales Pagadas", "Total Gas Used": "Gas total usado", "Total Holders": "Total de poseedores", @@ -288,6 +329,7 @@ "Tx ID": "ID de Tx", "Txs/Clauses": "Txs/Cláusulas", "Type": "Tipo", + "Unique Clients": "Clientes únicos", "Unknown": "Desconocido", "Usage": "Uso", "USD": "USD", @@ -300,6 +342,7 @@ "Validators": "Validadores", "Value": "Valor", "VeChain": "VeChain", + "Version": "Versión", "VET": "VET", "VET Balance": "Saldo VET", "VET Price": "Precio VET", diff --git a/i18n/languages/fr.json b/i18n/languages/fr.json index 5b2d0c34..3a16536b 100644 --- a/i18n/languages/fr.json +++ b/i18n/languages/fr.json @@ -2,6 +2,7 @@ "1D": "1J", "1M": "1M", "1Y": "1A", + "A2A Agent Card": "Carte d'agent A2A", "Account": "Compte", "Active": "Actif", "Active Stake": "Active Stake", @@ -11,12 +12,18 @@ "AFPT": "AFPT", "AFPU": "AFPU", "Age": "Âge", + "Agent": "Agent", + "Agent ID": "ID de l'agent", + "Agent Overview": "Aperçu de l'agent", + "Agent Registry": "Registre d'agents", + "AI Agent": "Agent IA", "All": "Tous", "All Time": "Tout le temps", "Amount": "Montant", "Attributes": "Attributs", "Average Fees Per Transaction (AFPT)": "Average Fees Per Transaction (AFPT)", "Average Fees Per User (AFPU)": "Frais Moyens par Utilisateur (AFPU)", + "Average Rating": "Note moyenne", "Avg AFPT": "Avg AFPT", "Avg AFPU": "AFPU Moy.", "Avg Gas Limit/Block": "Limite de gaz moyenne/bloc", @@ -54,6 +61,7 @@ "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.": "La clause n°{{index}} avec le selector {{selector}} a revert immédiatement sans raison décodée. Cela signifie souvent que la calldata a été encodée avec une ABI obsolète ou une signature de fonction incorrecte.", "Clause details": "Détails de la clause", "Clauses": "Clauses", + "Client": "Client", "Close navigation menu": "Close navigation menu", "Co2e": "Co2e", "CO2e emitted": "CO2e émis", @@ -73,6 +81,7 @@ "Created contract address": "Adresse du contrat créé", "Created On": "Créé le", "Creation Transaction": "Transaction de création", + "Creator": "Créateur", "Cycle duration": "Durée du cycle", "Cycle left": "Cycle restant", "Daily": "Quotidien", @@ -81,6 +90,7 @@ "Date": "Date", "Date & Time": "Date et heure", "Date time": "Date et heure", + "Deactivated": "Désactivé", "Decode": "Décoder", "Decoded": "Décodé", "decoded": "décodé", @@ -96,10 +106,13 @@ "details": "détails", "Dev mode": "Mode dev", "DEX Trades": "DEX Trades", + "Disabled": "Désactivé", "Earned Rewards": "Récompenses gagnées", "emitter": "émetteur", + "Enabled": "Activé", "Endorsed validators": "Validateurs soutenus", "Endorser": "Endorseur", + "Endpoint": "Point de terminaison", "Enter a valid URL": "Saisissez une URL valide", "Events": "Événements", "events": "événements", @@ -111,6 +124,7 @@ "Fee": "Frais", "Fee delegated to": "Frais délégués à", "Fee Paid": "Frais payés", + "Feedback": "Commentaires", "Fees, Gas and VTHO": "Frais, Gas et VTHO", "Finalized": "Finalisé", "Finalizing": "Finalisation", @@ -136,6 +150,7 @@ "indexed": "indexé", "Indexer URL must not include /api or /v": "L'URL de l'indexer ne doit pas inclure /api ou /v", "Input data": "Données d'entrée", + "Input Modes": "Modes d'entrée", "input-data": "données d'entrée", "Inspect tool": "Outil d'inspection", "Last page": "Dernière page", @@ -145,6 +160,7 @@ "Market Cap": "Capitalisation boursière", "Marketplace": "Marketplace", "Max Fee per Gas": "Frais max par Gas", + "Metadata": "Métadonnées", "Metadata not found at this uri": "Métadonnées non trouvées à cette URI", "Metrics": "Métriques", "Mint": "Émettre", @@ -171,8 +187,13 @@ "No contract creation": "Aucune création de contrat", "No contracts": "Aucun contrat", "No events": "Aucun événement", + "No feedback available": "Aucun commentaire disponible", + "No feedback yet": "Aucun commentaire pour l'instant", "No image": "Pas d'image", "No NFTs": "Aucun NFT", + "No quality data available": "Aucune donnée de qualité disponible", + "No services listed": "Aucun service répertorié", + "No statistics available": "Aucune statistique disponible", "No token transfers": "Aucun transfert de tokens", "No token transfers have been recorded yet": "Aucun transfert de tokens n'a encore été enregistré", "No tokens": "Aucun token", @@ -183,9 +204,12 @@ "Not delegated": "Non délégué", "Now": "Maintenant", "of": "de", + "On-chain Identity": "Identité on-chain", "Oops! Something went wrong": "Oups! Une erreur s'est produite", "Open navigation menu": "Open navigation menu", "Origin": "Origine", + "Output Modes": "Modes de sortie", + "Overview": "Aperçu", "Owned by": "Appartient à", "Owned Contracts": "Contrats Possédés", "Page": "Page", @@ -199,37 +223,50 @@ "Price": "Prix", "Priority Fee per Gas": "Frais de priorité par Gas", "Privacy Policy": "Politique de confidentialité", + "Quality": "Qualité", + "Rating": "Note", "Raw": "Brut", "raw": "brut", + "Raw Metadata": "Métadonnées brutes", + "Registered": "Enregistré", "Reliability": "Fiabilité", + "Reputation Registry": "Registre de réputation", "Reset": "Réinitialiser", "Resources": "Ressources", "Revert Reason": "Raison du revert", "Reverted": "Rétabli", + "Revoked": "Révoqué", "Rewards": "Récompenses", "Rows": "Lignes", "Rows per page": "Lignes par page", "Sale": "Vente", "Save": "Enregistrer", + "Schema": "Schéma", "Search": "Search", "Search for blocks, transactions or accounts": "Rechercher des blocs, transactions ou comptes", "Select Currency": "Sélectionner la devise", "Select Language": "Sélectionner la langue", + "Services": "Services", "Show": "Afficher", "Show All": "Tout afficher", "Show Less": "Afficher moins", "Signer": "Signataire", "Size": "Taille", + "Skills": "Compétences", "Solo indexer URL": "URL de l'indexer Solo", "Solo node URL": "URL du nœud Solo", "Something went wrong 😬": "Une erreur s'est produite 😬", "Staking NFTs": "Staking NFTs", "Stargate": "Stargate", "StarGate Docs": "Documentation StarGate", + "Statistics": "Statistiques", "Status": "Statut", + "Streaming": "Streaming", "success": "succès", "Support": "Support", "Support Center": "Centre d'assistance", + "Supported Trust": "Confiance prise en charge", + "Suspended": "Suspendu", "Symbol": "Symbole", "Terms of Service": "Conditions d'utilisation", "Testnet": "Testnet", @@ -242,6 +279,9 @@ "This account has not deployed any contracts yet": "Ce compte n'a encore déployé aucun contrat", "This account has not made any transactions yet": "Ce compte n'a effectué aucune transaction pour le moment", "This account has not made any transfers yet": "Ce compte n'a effectué aucun transfert pour le moment", + "This agent does not publish an on-chain reputation registry": "Cet agent ne publie pas de registre de réputation on-chain", + "This agent has not advertised any services yet": "Cet agent n'a encore annoncé aucun service", + "This agent has not received any feedback yet": "Cet agent n'a encore reçu aucun commentaire", "This clause has no contract creation": "Cette clause n'a pas de création de contrat", "This page does not exist": "Cette page n'existe pas", "This transaction has no events": "Cette transaction n'a aucun événement", @@ -261,6 +301,7 @@ "Total Clauses": "Clauses totales", "Total Earned": "Total gagné", "Total EUR": "Total EUR", + "Total Feedback": "Total des commentaires", "Total Fees Paid": "Frais Totaux Payés", "Total Gas Used": "Gas total utilisé", "Total Holders": "Nombre total de détenteurs", @@ -288,6 +329,7 @@ "Tx ID": "ID Tx", "Txs/Clauses": "Txs/Clauses", "Type": "Type", + "Unique Clients": "Clients uniques", "Unknown": "Inconnu", "Usage": "Utilisation", "USD": "USD", @@ -300,6 +342,7 @@ "Validators": "Validateurs", "Value": "Valeur", "VeChain": "VeChain", + "Version": "Version", "VET": "VET", "VET Balance": "Solde VET", "VET Price": "Prix VET", diff --git a/i18n/languages/it.json b/i18n/languages/it.json index 50bfc4b1..35e903ba 100644 --- a/i18n/languages/it.json +++ b/i18n/languages/it.json @@ -2,6 +2,7 @@ "1D": "1G", "1M": "1M", "1Y": "1A", + "A2A Agent Card": "Scheda agente A2A", "Account": "Account", "Active": "Attivo", "Active Stake": "Active Stake", @@ -11,12 +12,18 @@ "AFPT": "AFPT", "AFPU": "AFPU", "Age": "Età", + "Agent": "Agente", + "Agent ID": "ID agente", + "Agent Overview": "Panoramica dell'agente", + "Agent Registry": "Registro degli agenti", + "AI Agent": "Agente IA", "All": "Tutti", "All Time": "Tutto il tempo", "Amount": "Importo", "Attributes": "Attributi", "Average Fees Per Transaction (AFPT)": "Average Fees Per Transaction (AFPT)", "Average Fees Per User (AFPU)": "Commissioni Medie per Utente (AFPU)", + "Average Rating": "Valutazione media", "Avg AFPT": "Avg AFPT", "Avg AFPU": "AFPU Medio", "Avg Gas Limit/Block": "Limite medio di Gas/Blocco", @@ -54,6 +61,7 @@ "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.": "La clausola #{{index}} con selector {{selector}} è andata in revert immediatamente senza un motivo decodificato. Questo spesso significa che la calldata è stata codificata con un'ABI obsoleta o una firma di funzione errata.", "Clause details": "Dettagli clausola", "Clauses": "Clausole", + "Client": "Client", "Close navigation menu": "Close navigation menu", "Co2e": "Co2e", "CO2e emitted": "CO2e emesse", @@ -73,6 +81,7 @@ "Created contract address": "Indirizzo contratto creato", "Created On": "Creato il", "Creation Transaction": "Transazione di creazione", + "Creator": "Creatore", "Cycle duration": "Durata ciclo", "Cycle left": "Cicli rimanenti", "Daily": "Giornaliero", @@ -81,6 +90,7 @@ "Date": "Data", "Date & Time": "Data e Ora", "Date time": "Data e ora", + "Deactivated": "Disattivato", "Decode": "Decodifica", "Decoded": "Decodificato", "decoded": "decodificato", @@ -96,10 +106,13 @@ "details": "dettagli", "Dev mode": "Modalità dev", "DEX Trades": "DEX Trades", + "Disabled": "Disabilitato", "Earned Rewards": "Ricompense guadagnate", "emitter": "emittente", + "Enabled": "Abilitato", "Endorsed validators": "Validatori sostenuti", "Endorser": "Sostenitore", + "Endpoint": "Endpoint", "Enter a valid URL": "Inserisci un URL valido", "Events": "Eventi", "events": "eventi", @@ -111,6 +124,7 @@ "Fee": "Commissione", "Fee delegated to": "Commissione delegata a", "Fee Paid": "Commissione Pagata", + "Feedback": "Feedback", "Fees, Gas and VTHO": "Commissioni, Gas e VTHO", "Finalized": "Finalizzato", "Finalizing": "Finalizzazione", @@ -136,6 +150,7 @@ "indexed": "indicizzato", "Indexer URL must not include /api or /v": "L'URL dell'indexer non deve includere /api o /v", "Input data": "Dati di input", + "Input Modes": "Modalità di input", "input-data": "dati di input", "Inspect tool": "Strumento di ispezione", "Last page": "Ultima pagina", @@ -145,6 +160,7 @@ "Market Cap": "Capitalizzazione di Mercato", "Marketplace": "Marketplace", "Max Fee per Gas": "Commissione massima per Gas", + "Metadata": "Metadati", "Metadata not found at this uri": "Metadati non trovati a questo URI", "Metrics": "Metriche", "Mint": "Conia", @@ -171,8 +187,13 @@ "No contract creation": "Nessuna creazione di contratto", "No contracts": "Nessun contratto", "No events": "Nessun evento", + "No feedback available": "Nessun feedback disponibile", + "No feedback yet": "Ancora nessun feedback", "No image": "Nessuna immagine", "No NFTs": "Nessun NFT", + "No quality data available": "Nessun dato di qualità disponibile", + "No services listed": "Nessun servizio elencato", + "No statistics available": "Nessuna statistica disponibile", "No token transfers": "Nessun trasferimento di token", "No token transfers have been recorded yet": "Non sono stati ancora registrati trasferimenti di token", "No tokens": "Nessun token", @@ -183,9 +204,12 @@ "Not delegated": "Non delegato", "Now": "Adesso", "of": "di", + "On-chain Identity": "Identità on-chain", "Oops! Something went wrong": "Ops! Qualcosa è andato storto", "Open navigation menu": "Open navigation menu", "Origin": "Origine", + "Output Modes": "Modalità di output", + "Overview": "Panoramica", "Owned by": "Di proprietà di", "Owned Contracts": "Contratti Posseduti", "Page": "Pagina", @@ -199,37 +223,50 @@ "Price": "Prezzo", "Priority Fee per Gas": "Commissione prioritaria per Gas", "Privacy Policy": "Informativa sulla Privacy", + "Quality": "Qualità", + "Rating": "Valutazione", "Raw": "Grezzo", "raw": "grezzo", + "Raw Metadata": "Metadati grezzi", + "Registered": "Registrato", "Reliability": "Affidabilità", + "Reputation Registry": "Registro di reputazione", "Reset": "Resetta", "Resources": "Risorse", "Revert Reason": "Motivo dell'annullamento", "Reverted": "Riportato", + "Revoked": "Revocato", "Rewards": "Ricompense", "Rows": "Righe", "Rows per page": "Righe per pagina", "Sale": "Vendita", "Save": "Salva", + "Schema": "Schema", "Search": "Search", "Search for blocks, transactions or accounts": "Cerca blocchi, transazioni o account", "Select Currency": "Seleziona valuta", "Select Language": "Seleziona lingua", + "Services": "Servizi", "Show": "Mostra", "Show All": "Mostra tutto", "Show Less": "Mostra meno", "Signer": "Firmatario", "Size": "Dimensione", + "Skills": "Competenze", "Solo indexer URL": "URL indexer Solo", "Solo node URL": "URL node Solo", "Something went wrong 😬": "Qualcosa è andato storto 😬", "Staking NFTs": "Staking NFT", "Stargate": "Stargate", "StarGate Docs": "StarGate Docs", + "Statistics": "Statistiche", "Status": "Stato", + "Streaming": "Streaming", "success": "successo", "Support": "Supporto", "Support Center": "Centro Assistenza", + "Supported Trust": "Fiducia supportata", + "Suspended": "Sospeso", "Symbol": "Simbolo", "Terms of Service": "Termini di Servizio", "Testnet": "Testnet", @@ -242,6 +279,9 @@ "This account has not deployed any contracts yet": "Questo account non ha ancora distribuito nessun contratto", "This account has not made any transactions yet": "Questo account non ha ancora effettuato transazioni", "This account has not made any transfers yet": "Questo account non ha ancora effettuato trasferimenti", + "This agent does not publish an on-chain reputation registry": "Questo agente non pubblica un registro di reputazione on-chain", + "This agent has not advertised any services yet": "Questo agente non ha ancora pubblicato alcun servizio", + "This agent has not received any feedback yet": "Questo agente non ha ancora ricevuto feedback", "This clause has no contract creation": "Questa clausola non ha creazione di contratto", "This page does not exist": "Questa pagina non esiste", "This transaction has no events": "Questa transazione non ha eventi", @@ -261,6 +301,7 @@ "Total Clauses": "Clausole Totali", "Total Earned": "Totale Guadagnato", "Total EUR": "Totale EUR", + "Total Feedback": "Feedback totali", "Total Fees Paid": "Commissioni Totali Pagate", "Total Gas Used": "Gas totale utilizzato", "Total Holders": "Titolari totali", @@ -288,6 +329,7 @@ "Tx ID": "ID Tx", "Txs/Clauses": "Txs/Clausole", "Type": "Tipo", + "Unique Clients": "Client unici", "Unknown": "Sconosciuto", "Usage": "Utilizzo", "USD": "USD", @@ -300,6 +342,7 @@ "Validators": "Validatori", "Value": "Valore", "VeChain": "VeChain", + "Version": "Versione", "VET": "VET", "VET Balance": "Saldo VET", "VET Price": "Prezzo VET", diff --git a/i18n/languages/ja.json b/i18n/languages/ja.json index ab2d3e45..8787793b 100644 --- a/i18n/languages/ja.json +++ b/i18n/languages/ja.json @@ -2,6 +2,7 @@ "1D": "1日", "1M": "1ヶ月", "1Y": "1年", + "A2A Agent Card": "A2A エージェントカード", "Account": "アカウント", "Active": "アクティブ", "Active Stake": "Active Stake", @@ -11,12 +12,18 @@ "AFPT": "AFPT", "AFPU": "AFPU", "Age": "経過時間", + "Agent": "エージェント", + "Agent ID": "エージェントID", + "Agent Overview": "エージェント概要", + "Agent Registry": "エージェントレジストリ", + "AI Agent": "AIエージェント", "All": "すべて", "All Time": "全期間", "Amount": "金額", "Attributes": "属性", "Average Fees Per Transaction (AFPT)": "Average Fees Per Transaction (AFPT)", "Average Fees Per User (AFPU)": "ユーザーあたりの平均手数料 (AFPU)", + "Average Rating": "平均評価", "Avg AFPT": "Avg AFPT", "Avg AFPU": "平均AFPU", "Avg Gas Limit/Block": "平均ガスリミット/ブロック", @@ -54,6 +61,7 @@ "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.": "セレクタ {{selector}} を持つ clause #{{index}} は、デコード可能な理由なしに直ちに revert しました。これは calldata が古い ABI か誤った関数シグネチャでエンコードされたことを示す場合がよくあります。", "Clause details": "条項の詳細", "Clauses": "条項", + "Client": "クライアント", "Close navigation menu": "Close navigation menu", "Co2e": "CO2e", "CO2e emitted": "排出されたCO2e", @@ -73,6 +81,7 @@ "Created contract address": "作成されたコントラクトアドレス", "Created On": "作成日", "Creation Transaction": "作成トランザクション", + "Creator": "作成者", "Cycle duration": "サイクル期間", "Cycle left": "残りサイクル", "Daily": "毎日", @@ -81,6 +90,7 @@ "Date": "日付", "Date & Time": "日時", "Date time": "日時", + "Deactivated": "無効", "Decode": "デコード", "Decoded": "デコード済み", "decoded": "デコード済み", @@ -96,10 +106,13 @@ "details": "詳細", "Dev mode": "開発モード", "DEX Trades": "DEX Trades", + "Disabled": "無効", "Earned Rewards": "獲得報酬", "emitter": "エミッター", + "Enabled": "有効", "Endorsed validators": "エンドースしたバリデーター", "Endorser": "エンドーサー", + "Endpoint": "エンドポイント", "Enter a valid URL": "有効な URL を入力してください", "Events": "イベント", "events": "イベント", @@ -111,6 +124,7 @@ "Fee": "手数料", "Fee delegated to": "手数料委任先", "Fee Paid": "支払手数料", + "Feedback": "フィードバック", "Fees, Gas and VTHO": "手数料、ガス、VTHO", "Finalized": "完了", "Finalizing": "最終化中", @@ -136,6 +150,7 @@ "indexed": "インデックス付き", "Indexer URL must not include /api or /v": "インデクサー URL に /api または /v を含めないでください", "Input data": "入力データ", + "Input Modes": "入力モード", "input-data": "入力データ", "Inspect tool": "検査ツール", "Last page": "最後のページ", @@ -145,6 +160,7 @@ "Market Cap": "時価総額", "Marketplace": "マーケットプレイス", "Max Fee per Gas": "ガス最大手数料", + "Metadata": "メタデータ", "Metadata not found at this uri": "このURIでメタデータが見つかりません", "Metrics": "メトリクス", "Mint": "ミント", @@ -171,8 +187,13 @@ "No contract creation": "コントラクトの作成なし", "No contracts": "コントラクトなし", "No events": "イベントなし", + "No feedback available": "フィードバックはありません", + "No feedback yet": "まだフィードバックがありません", "No image": "画像なし", "No NFTs": "NFTがありません", + "No quality data available": "品質データはありません", + "No services listed": "サービスがありません", + "No statistics available": "統計はありません", "No token transfers": "トークン転送なし", "No token transfers have been recorded yet": "トークン転送はまだ記録されていません", "No tokens": "トークンなし", @@ -183,9 +204,12 @@ "Not delegated": "未委任", "Now": "今", "of": "の", + "On-chain Identity": "オンチェーンID", "Oops! Something went wrong": "おっと!問題が発生しました", "Open navigation menu": "Open navigation menu", "Origin": "オリジン", + "Output Modes": "出力モード", + "Overview": "概要", "Owned by": "所有者", "Owned Contracts": "所有済みコントラクト", "Page": "ページ", @@ -199,37 +223,50 @@ "Price": "価格", "Priority Fee per Gas": "ガス優先手数料", "Privacy Policy": "プライバシーポリシー", + "Quality": "品質", + "Rating": "評価", "Raw": "生データ", "raw": "生データ", + "Raw Metadata": "生メタデータ", + "Registered": "登録日", "Reliability": "信頼性", + "Reputation Registry": "評価レジストリ", "Reset": "リセット", "Resources": "リソース", "Revert Reason": "リバート理由", "Reverted": "差し戻し", + "Revoked": "取り消し済み", "Rewards": "報酬", "Rows": "行数", "Rows per page": "ページごとの行数", "Sale": "販売", "Save": "保存", + "Schema": "スキーマ", "Search": "Search", "Search for blocks, transactions or accounts": "ブロック、トランザクション、またはアカウントを検索", "Select Currency": "通貨を選択", "Select Language": "言語を選択", + "Services": "サービス", "Show": "表示", "Show All": "すべて表示", "Show Less": "表示を減らす", "Signer": "署名者", "Size": "サイズ", + "Skills": "スキル", "Solo indexer URL": "Solo インデクサー URL", "Solo node URL": "Solo ノード URL", "Something went wrong 😬": "問題が発生しました 😬", "Staking NFTs": "staking NFT", "Stargate": "Stargate", "StarGate Docs": "StarGate ドキュメント", + "Statistics": "統計", "Status": "ステータス", + "Streaming": "ストリーミング", "success": "成功", "Support": "サポート", "Support Center": "サポートセンター", + "Supported Trust": "対応する信頼モデル", + "Suspended": "一時停止", "Symbol": "シンボル", "Terms of Service": "利用規約", "Testnet": "Testnet", @@ -242,6 +279,9 @@ "This account has not deployed any contracts yet": "このアカウントはまだコントラクトをデプロイしていません", "This account has not made any transactions yet": "このアカウントはまだトランザクションを行っていません", "This account has not made any transfers yet": "このアカウントはまだ送金を行っていません", + "This agent does not publish an on-chain reputation registry": "このエージェントはオンチェーンの評価レジストリを公開していません", + "This agent has not advertised any services yet": "このエージェントはまだサービスを公開していません", + "This agent has not received any feedback yet": "このエージェントはまだフィードバックを受け取っていません", "This clause has no contract creation": "この条項にはコントラクト作成がありません", "This page does not exist": "このページは存在しません", "This transaction has no events": "このトランザクションにはイベントがありません", @@ -261,6 +301,7 @@ "Total Clauses": "合計条項数", "Total Earned": "合計獲得", "Total EUR": "合計 EUR", + "Total Feedback": "フィードバック総数", "Total Fees Paid": "支払い手数料合計", "Total Gas Used": "合計ガス使用量", "Total Holders": "保有者合計", @@ -288,6 +329,7 @@ "Tx ID": "取引ID", "Txs/Clauses": "取引/条件", "Type": "タイプ", + "Unique Clients": "ユニーククライアント数", "Unknown": "不明", "Usage": "使用量", "USD": "USD", @@ -300,6 +342,7 @@ "Validators": "バリデータ", "Value": "値", "VeChain": "VeChain", + "Version": "バージョン", "VET": "VET", "VET Balance": "VET残高", "VET Price": "VET価格", diff --git a/i18n/languages/pt.json b/i18n/languages/pt.json index c393660a..28a6a6a5 100644 --- a/i18n/languages/pt.json +++ b/i18n/languages/pt.json @@ -2,6 +2,7 @@ "1D": "1D", "1M": "1M", "1Y": "1A", + "A2A Agent Card": "Cartão de agente A2A", "Account": "Conta", "Active": "Ativo", "Active Stake": "Active Stake", @@ -11,12 +12,18 @@ "AFPT": "AFPT", "AFPU": "AFPU", "Age": "Idade", + "Agent": "Agente", + "Agent ID": "ID do agente", + "Agent Overview": "Visão geral do agente", + "Agent Registry": "Registro de agentes", + "AI Agent": "Agente de IA", "All": "Todos", "All Time": "Todo o Tempo", "Amount": "Quantidade", "Attributes": "Atributos", "Average Fees Per Transaction (AFPT)": "Average Fees Per Transaction (AFPT)", "Average Fees Per User (AFPU)": "Taxas Médias por Usuário (AFPU)", + "Average Rating": "Avaliação média", "Avg AFPT": "Avg AFPT", "Avg AFPU": "AFPU Méd.", "Avg Gas Limit/Block": "Média de Limite de Gás/Bloco", @@ -54,6 +61,7 @@ "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.": "A cláusula #{{index}} com o selector {{selector}} reverteu imediatamente sem um motivo decodificado. Isso geralmente significa que a calldata foi codificada com uma ABI desatualizada ou com uma assinatura de função incorreta.", "Clause details": "Detalhes da Cláusula", "Clauses": "Cláusulas", + "Client": "Cliente", "Close navigation menu": "Close navigation menu", "Co2e": "CO2e", "CO2e emitted": "CO2e emitido", @@ -73,6 +81,7 @@ "Created contract address": "Endereço do contrato criado", "Created On": "Criado em", "Creation Transaction": "Transação de criação", + "Creator": "Criador", "Cycle duration": "Duração do ciclo", "Cycle left": "Ciclos restantes", "Daily": "Diário", @@ -81,6 +90,7 @@ "Date": "Data", "Date & Time": "Data e hora", "Date time": "Data e hora", + "Deactivated": "Desativado", "Decode": "Decodificar", "Decoded": "Decodificado", "decoded": "decodificado", @@ -96,10 +106,13 @@ "details": "detalhes", "Dev mode": "Modo dev", "DEX Trades": "DEX Trades", + "Disabled": "Desativado", "Earned Rewards": "Recompensas ganhas", "emitter": "emissor", + "Enabled": "Ativado", "Endorsed validators": "Validadores endossados", "Endorser": "Endossador", + "Endpoint": "Endpoint", "Enter a valid URL": "Insira uma URL válida", "Events": "Eventos", "events": "eventos", @@ -111,6 +124,7 @@ "Fee": "Taxa", "Fee delegated to": "Taxa delegada para", "Fee Paid": "Taxa paga", + "Feedback": "Comentários", "Fees, Gas and VTHO": "Taxas, Gas e VTHO", "Finalized": "Finalizado", "Finalizing": "Finalizando", @@ -136,6 +150,7 @@ "indexed": "indexado", "Indexer URL must not include /api or /v": "A URL do indexador não deve incluir /api ou /v", "Input data": "Dados de entrada", + "Input Modes": "Modos de entrada", "input-data": "dados de entrada", "Inspect tool": "Ferramenta de inspeção", "Last page": "Última página", @@ -145,6 +160,7 @@ "Market Cap": "Valor de Mercado", "Marketplace": "Marketplace", "Max Fee per Gas": "Taxa máxima por Gas", + "Metadata": "Metadados", "Metadata not found at this uri": "Metadados não encontrados neste URI", "Metrics": "Métricas", "Mint": "Mintar", @@ -171,8 +187,13 @@ "No contract creation": "Nenhuma criação de contrato", "No contracts": "Nenhum contrato", "No events": "Nenhum evento", + "No feedback available": "Nenhum comentário disponível", + "No feedback yet": "Ainda não há comentários", "No image": "Sem imagem", "No NFTs": "Sem NFTs", + "No quality data available": "Nenhum dado de qualidade disponível", + "No services listed": "Nenhum serviço listado", + "No statistics available": "Nenhuma estatística disponível", "No token transfers": "Nenhuma transferência de token", "No token transfers have been recorded yet": "Nenhuma transferência de token foi registrada ainda", "No tokens": "Nenhum token", @@ -183,9 +204,12 @@ "Not delegated": "Não delegado", "Now": "Agora", "of": "de", + "On-chain Identity": "Identidade on-chain", "Oops! Something went wrong": "Opa! Algo deu errado", "Open navigation menu": "Open navigation menu", "Origin": "Origem", + "Output Modes": "Modos de saída", + "Overview": "Visão geral", "Owned by": "Pertencente a", "Owned Contracts": "Contratos Possuídos", "Page": "Página", @@ -199,37 +223,50 @@ "Price": "Preço", "Priority Fee per Gas": "Taxa de prioridade por Gas", "Privacy Policy": "Política de Privacidade", + "Quality": "Qualidade", + "Rating": "Avaliação", "Raw": "Bruto", "raw": "bruto", + "Raw Metadata": "Metadados brutos", + "Registered": "Registrado", "Reliability": "Confiabilidade", + "Reputation Registry": "Registro de reputação", "Reset": "Redefinir", "Resources": "Recursos", "Revert Reason": "Motivo da reversão", "Reverted": "Revertido", + "Revoked": "Revogado", "Rewards": "Recompensas", "Rows": "Linhas", "Rows per page": "Linhas por página", "Sale": "Venda", "Save": "Salvar", + "Schema": "Esquema", "Search": "Search", "Search for blocks, transactions or accounts": "Pesquisar por blocos, transações ou contas", "Select Currency": "Selecionar moeda", "Select Language": "Selecionar idioma", + "Services": "Serviços", "Show": "Mostrar", "Show All": "Mostrar tudo", "Show Less": "Mostrar menos", "Signer": "Assinante", "Size": "Tamanho", + "Skills": "Habilidades", "Solo indexer URL": "URL do indexador Solo", "Solo node URL": "URL do nó Solo", "Something went wrong 😬": "Algo deu errado 😬", "Staking NFTs": "Staking de NFTs", "Stargate": "Stargate", "StarGate Docs": "StarGate Docs", + "Statistics": "Estatísticas", "Status": "Status", + "Streaming": "Streaming", "success": "sucesso", "Support": "Suporte", "Support Center": "Central de Suporte", + "Supported Trust": "Confiança suportada", + "Suspended": "Suspenso", "Symbol": "Símbolo", "Terms of Service": "Termos de Serviço", "Testnet": "Testnet", @@ -242,6 +279,9 @@ "This account has not deployed any contracts yet": "Esta conta ainda não implantou nenhum contrato", "This account has not made any transactions yet": "Esta conta ainda não fez nenhuma transação", "This account has not made any transfers yet": "Esta conta ainda não fez nenhuma transferência", + "This agent does not publish an on-chain reputation registry": "Este agente não publica um registro de reputação on-chain", + "This agent has not advertised any services yet": "Este agente ainda não anunciou nenhum serviço", + "This agent has not received any feedback yet": "Este agente ainda não recebeu comentários", "This clause has no contract creation": "Esta cláusula não possui criação de contrato", "This page does not exist": "Esta página não existe", "This transaction has no events": "Esta transação não possui eventos", @@ -261,6 +301,7 @@ "Total Clauses": "Total de Cláusulas", "Total Earned": "Total Ganho", "Total EUR": "Total em EUR", + "Total Feedback": "Total de comentários", "Total Fees Paid": "Taxas Totais Pagas", "Total Gas Used": "Gas total usado", "Total Holders": "Total de Detentores", @@ -288,6 +329,7 @@ "Tx ID": "ID da Tx", "Txs/Clauses": "Txs/Cláusulas", "Type": "Tipo", + "Unique Clients": "Clientes únicos", "Unknown": "Desconhecido", "Usage": "Uso", "USD": "USD", @@ -300,6 +342,7 @@ "Validators": "Validadores", "Value": "Valor", "VeChain": "VeChain", + "Version": "Versão", "VET": "VET", "VET Balance": "Saldo de VET", "VET Price": "Preço do VET", diff --git a/i18n/languages/ru.json b/i18n/languages/ru.json index 2e967e24..609c2665 100644 --- a/i18n/languages/ru.json +++ b/i18n/languages/ru.json @@ -2,6 +2,7 @@ "1D": "1Д", "1M": "1М", "1Y": "1Г", + "A2A Agent Card": "Карточка агента A2A", "Account": "Аккаунт", "Active": "Активен", "Active Stake": "Active Stake", @@ -11,12 +12,18 @@ "AFPT": "AFPT", "AFPU": "AFPU", "Age": "Возраст", + "Agent": "Агент", + "Agent ID": "ID агента", + "Agent Overview": "Обзор агента", + "Agent Registry": "Реестр агентов", + "AI Agent": "ИИ-агент", "All": "Все", "All Time": "За всё время", "Amount": "Сумма", "Attributes": "Атрибуты", "Average Fees Per Transaction (AFPT)": "Average Fees Per Transaction (AFPT)", "Average Fees Per User (AFPU)": "Средние комиссии на пользователя (AFPU)", + "Average Rating": "Средняя оценка", "Avg AFPT": "Avg AFPT", "Avg AFPU": "Сред. AFPU", "Avg Gas Limit/Block": "Средний лимит газа/блок", @@ -54,6 +61,7 @@ "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.": "Клауза №{{index}} с selector {{selector}} завершилась revert сразу без декодированной причины. Это часто означает, что calldata была закодирована с устаревшим ABI или неверной сигнатурой функции.", "Clause details": "Детали условия", "Clauses": "Клаузы", + "Client": "Клиент", "Close navigation menu": "Close navigation menu", "Co2e": "Эквивалент CO2", "CO2e emitted": "Выброшено CO2e", @@ -73,6 +81,7 @@ "Created contract address": "Адрес созданного контракта", "Created On": "Создано", "Creation Transaction": "Транзакция создания", + "Creator": "Создатель", "Cycle duration": "Длительность цикла", "Cycle left": "Осталось до конца цикла", "Daily": "Ежедневно", @@ -81,6 +90,7 @@ "Date": "Дата", "Date & Time": "Дата и время", "Date time": "Дата и время", + "Deactivated": "Деактивирован", "Decode": "Декодировать", "Decoded": "Декодировано", "decoded": "декодировано", @@ -96,10 +106,13 @@ "details": "подробности", "Dev mode": "Режим разработчика", "DEX Trades": "DEX Trades", + "Disabled": "Отключено", "Earned Rewards": "Полученные награды", "emitter": "эмитент", + "Enabled": "Включено", "Endorsed validators": "Поддержанные валидаторы", "Endorser": "Поручитель", + "Endpoint": "Конечная точка", "Enter a valid URL": "Введите корректный URL", "Events": "События", "events": "события", @@ -111,6 +124,7 @@ "Fee": "Комиссия", "Fee delegated to": "Комиссия делегирована", "Fee Paid": "Оплаченная комиссия", + "Feedback": "Отзывы", "Fees, Gas and VTHO": "Комиссии, газ и VTHO", "Finalized": "Финализировано", "Finalizing": "Финализация", @@ -136,6 +150,7 @@ "indexed": "проиндексировано", "Indexer URL must not include /api or /v": "URL индексера не должен содержать /api или /v", "Input data": "Входные данные", + "Input Modes": "Режимы ввода", "input-data": "входные данные", "Inspect tool": "Инструмент инспекции", "Last page": "Последняя страница", @@ -145,6 +160,7 @@ "Market Cap": "Рыночная капитализация", "Marketplace": "Маркетплейс", "Max Fee per Gas": "Максимальная комиссия за Gas", + "Metadata": "Метаданные", "Metadata not found at this uri": "Метаданные по этому адресу не найдены", "Metrics": "Метрики", "Mint": "Чеканить", @@ -171,8 +187,13 @@ "No contract creation": "Создание контракта отсутствует", "No contracts": "Нет контрактов", "No events": "События отсутствуют", + "No feedback available": "Отзывы недоступны", + "No feedback yet": "Отзывов пока нет", "No image": "Нет изображения", "No NFTs": "Нет NFT", + "No quality data available": "Данные о качестве недоступны", + "No services listed": "Сервисы не указаны", + "No statistics available": "Статистика недоступна", "No token transfers": "Нет переводов токенов", "No token transfers have been recorded yet": "Переводы токенов еще не зарегистрированы", "No tokens": "Токены отсутствуют", @@ -183,9 +204,12 @@ "Not delegated": "Не делегировано", "Now": "Сейчас", "of": "из", + "On-chain Identity": "Ончейн-идентификатор", "Oops! Something went wrong": "Ой! Что-то пошло не так", "Open navigation menu": "Open navigation menu", "Origin": "Источник", + "Output Modes": "Режимы вывода", + "Overview": "Обзор", "Owned by": "Владелец", "Owned Contracts": "Ваши контракты", "Page": "Страница", @@ -199,37 +223,50 @@ "Price": "Цена", "Priority Fee per Gas": "Приоритетная комиссия за Gas", "Privacy Policy": "Политика конфиденциальности", + "Quality": "Качество", + "Rating": "Оценка", "Raw": "Сырой вид", "raw": "сырой", + "Raw Metadata": "Необработанные метаданные", + "Registered": "Зарегистрирован", "Reliability": "Надежность", + "Reputation Registry": "Реестр репутации", "Reset": "Сбросить", "Resources": "Ресурсы", "Revert Reason": "Причина отката", "Reverted": "Отклонено", + "Revoked": "Отозвано", "Rewards": "Награды", "Rows": "Строки", "Rows per page": "Строк на странице", "Sale": "Продажа", "Save": "Сохранить", + "Schema": "Схема", "Search": "Search", "Search for blocks, transactions or accounts": "Поиск блоков, транзакций или аккаунтов", "Select Currency": "Выбрать валюту", "Select Language": "Выберите язык", + "Services": "Сервисы", "Show": "Показать", "Show All": "Показать все", "Show Less": "Показать меньше", "Signer": "Подписант", "Size": "Размер", + "Skills": "Навыки", "Solo indexer URL": "URL индексера Solo", "Solo node URL": "URL ноды Solo", "Something went wrong 😬": "Что-то пошло не так 😬", "Staking NFTs": "Staking NFT", "Stargate": "Stargate", "StarGate Docs": "Документация StarGate", + "Statistics": "Статистика", "Status": "Статус", + "Streaming": "Потоковая передача", "success": "успешно", "Support": "Поддержка", "Support Center": "Центр поддержки", + "Supported Trust": "Поддерживаемые модели доверия", + "Suspended": "Приостановлен", "Symbol": "Символ", "Terms of Service": "Условия использования", "Testnet": "Testnet", @@ -242,6 +279,9 @@ "This account has not deployed any contracts yet": "Этот аккаунт еще не развернул ни одного контракта", "This account has not made any transactions yet": "Этот аккаунт еще не совершил ни одной транзакции", "This account has not made any transfers yet": "Этот аккаунт еще не совершил ни одного перевода", + "This agent does not publish an on-chain reputation registry": "Этот агент не публикует ончейн-реестр репутации", + "This agent has not advertised any services yet": "Этот агент ещё не заявил ни одного сервиса", + "This agent has not received any feedback yet": "Этот агент ещё не получил отзывов", "This clause has no contract creation": "В этом пункте отсутствует создание контракта", "This page does not exist": "Эта страница не существует", "This transaction has no events": "В этой транзакции нет событий", @@ -261,6 +301,7 @@ "Total Clauses": "Всего условий", "Total Earned": "Всего заработано", "Total EUR": "Всего EUR", + "Total Feedback": "Всего отзывов", "Total Fees Paid": "Общая сумма уплаченных комиссий", "Total Gas Used": "Всего использовано Gas", "Total Holders": "Всего держателей", @@ -288,6 +329,7 @@ "Tx ID": "ID транзакции", "Txs/Clauses": "Транзакции/Условия", "Type": "Тип", + "Unique Clients": "Уникальные клиенты", "Unknown": "Неизвестно", "Usage": "Использование", "USD": "USD", @@ -300,6 +342,7 @@ "Validators": "Валидаторы", "Value": "Значение", "VeChain": "VeChain", + "Version": "Версия", "VET": "VET", "VET Balance": "Баланс VET", "VET Price": "Цена VET", diff --git a/i18n/languages/tr.json b/i18n/languages/tr.json index 1eac80fc..296504c0 100644 --- a/i18n/languages/tr.json +++ b/i18n/languages/tr.json @@ -2,6 +2,7 @@ "1D": "1G", "1M": "1A", "1Y": "1Y", + "A2A Agent Card": "A2A Ajan Kartı", "Account": "Hesap", "Active": "Aktif", "Active Stake": "Active Stake", @@ -11,12 +12,18 @@ "AFPT": "AFPT", "AFPU": "AFPU", "Age": "Yaş", + "Agent": "Ajan", + "Agent ID": "Ajan Kimliği", + "Agent Overview": "Ajan Genel Bakışı", + "Agent Registry": "Ajan Kaydı", + "AI Agent": "Yapay Zekâ Ajanı", "All": "Hepsi", "All Time": "Tüm Zamanlar", "Amount": "Miktar", "Attributes": "Öznitelikler", "Average Fees Per Transaction (AFPT)": "Average Fees Per Transaction (AFPT)", "Average Fees Per User (AFPU)": "Kullanıcı Başına Ortalama Ücret (AFPU)", + "Average Rating": "Ortalama Puan", "Avg AFPT": "Avg AFPT", "Avg AFPU": "Ort. AFPU", "Avg Gas Limit/Block": "Blok Başına Ortalama Gas Limiti", @@ -54,6 +61,7 @@ "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.": "{{selector}} selector'üne sahip #{{index}} maddesi, çözümlenmiş bir neden olmadan hemen revert etti. Bu genellikle calldata'nın eski bir ABI veya yanlış bir fonksiyon imzasıyla kodlandığı anlamına gelir.", "Clause details": "Madde detayları", "Clauses": "Maddeler", + "Client": "İstemci", "Close navigation menu": "Close navigation menu", "Co2e": "Co2e", "CO2e emitted": "Salınan CO2e", @@ -73,6 +81,7 @@ "Created contract address": "Oluşturulan sözleşme adresi", "Created On": "Oluşturulma Tarihi", "Creation Transaction": "Oluşturma İşlemi", + "Creator": "Oluşturan", "Cycle duration": "Döngü süresi", "Cycle left": "Kalan döngü", "Daily": "Günlük", @@ -81,6 +90,7 @@ "Date": "Tarih", "Date & Time": "Tarih ve Saat", "Date time": "Tarih saat", + "Deactivated": "Devre dışı", "Decode": "Çöz", "Decoded": "Çözümlendi", "decoded": "çözüldü", @@ -96,10 +106,13 @@ "details": "detaylar", "Dev mode": "Geliştirici modu", "DEX Trades": "DEX Trades", + "Disabled": "Devre dışı", "Earned Rewards": "Kazanılan ödüller", "emitter": "yayıncı", + "Enabled": "Etkin", "Endorsed validators": "Desteklenen validatorler", "Endorser": "Onaylayan", + "Endpoint": "Uç Nokta", "Enter a valid URL": "Geçerli bir URL girin", "Events": "Etkinlikler", "events": "olaylar", @@ -111,6 +124,7 @@ "Fee": "Ücret", "Fee delegated to": "Ücret şu adrese devredildi", "Fee Paid": "Ödenen Ücret", + "Feedback": "Geri Bildirim", "Fees, Gas and VTHO": "Ücretler, Gas ve VTHO", "Finalized": "Sonuçlandı", "Finalizing": "Sonuçlandırılıyor", @@ -136,6 +150,7 @@ "indexed": "indeksli", "Indexer URL must not include /api or /v": "Indexer URL'si /api veya /v içermemelidir", "Input data": "Girdi verisi", + "Input Modes": "Giriş Modları", "input-data": "girdi verisi", "Inspect tool": "Aracı İncele", "Last page": "Son sayfa", @@ -145,6 +160,7 @@ "Market Cap": "Piyasa Değeri", "Marketplace": "Pazar Yeri", "Max Fee per Gas": "Gas Başına Maksimum Ücret", + "Metadata": "Meta Veriler", "Metadata not found at this uri": "Bu URI'da metadata bulunamadı", "Metrics": "Metrikler", "Mint": "Bas", @@ -171,8 +187,13 @@ "No contract creation": "Sözleşme oluşturulmadı", "No contracts": "Sözleşme yok", "No events": "Etkinlik yok", + "No feedback available": "Geri bildirim yok", + "No feedback yet": "Henüz geri bildirim yok", "No image": "Görüntü Yok", "No NFTs": "NFT Yok", + "No quality data available": "Kalite verisi yok", + "No services listed": "Listelenen hizmet yok", + "No statistics available": "İstatistik yok", "No token transfers": "Token transferi yok", "No token transfers have been recorded yet": "Henüz token transferi kaydedilmedi", "No tokens": "Token yok", @@ -183,9 +204,12 @@ "Not delegated": "Delege Edilmedi", "Now": "Şimdi", "of": " / ", + "On-chain Identity": "Zincir Üzerinde Kimlik", "Oops! Something went wrong": "Bir şeyler yanlış gitti", "Open navigation menu": "Open navigation menu", "Origin": "Kaynak", + "Output Modes": "Çıkış Modları", + "Overview": "Genel Bakış", "Owned by": "Sahibi", "Owned Contracts": "Sahip Olunan Sözleşmeler", "Page": "Sayfa", @@ -199,37 +223,50 @@ "Price": "Fiyat", "Priority Fee per Gas": "Gas Başına Öncelik Ücreti", "Privacy Policy": "Gizlilik Politikası", + "Quality": "Kalite", + "Rating": "Puan", "Raw": "Ham", "raw": "ham", + "Raw Metadata": "Ham Meta Veriler", + "Registered": "Kaydedildi", "Reliability": "Güvenilirlik", + "Reputation Registry": "İtibar Kaydı", "Reset": "Sıfırla", "Resources": "Kaynaklar", "Revert Reason": "Geri Alma Nedeni", "Reverted": "Geri alındı", + "Revoked": "İptal edildi", "Rewards": "Ödüller", "Rows": "Satırlar", "Rows per page": "Sayfa başına satır", "Sale": "Satış", "Save": "Kaydet", + "Schema": "Şema", "Search": "Search", "Search for blocks, transactions or accounts": "Blok, işlem veya hesap ara", "Select Currency": "Para Birimi Seç", "Select Language": "Dil Seç", + "Services": "Hizmetler", "Show": "Göster", "Show All": "Tümünü Göster", "Show Less": "Daha Az Göster", "Signer": "İmzalayan", "Size": "Boyut", + "Skills": "Yetenekler", "Solo indexer URL": "Solo indexer URL'si", "Solo node URL": "Solo node URL'si", "Something went wrong 😬": "Bir şeyler ters gitti 😬", "Staking NFTs": "Staking NFT'leri", "Stargate": "Stargate", "StarGate Docs": "StarGate Dokümanları", + "Statistics": "İstatistikler", "Status": "Durum", + "Streaming": "Akış", "success": "başarılı", "Support": "Destek", "Support Center": "Destek Merkezi", + "Supported Trust": "Desteklenen Güven", + "Suspended": "Askıya alındı", "Symbol": "Sembol", "Terms of Service": "Hizmet Şartları", "Testnet": "Testnet", @@ -242,6 +279,9 @@ "This account has not deployed any contracts yet": "Bu hesap henüz herhangi bir sözleşme yayınlamadı", "This account has not made any transactions yet": "Bu hesap henüz hiç işlem yapmamış", "This account has not made any transfers yet": "Bu hesap henüz hiç transfer yapmamış", + "This agent does not publish an on-chain reputation registry": "Bu ajan zincir üzerinde bir itibar kaydı yayımlamıyor", + "This agent has not advertised any services yet": "Bu ajan henüz herhangi bir hizmet duyurmadı", + "This agent has not received any feedback yet": "Bu ajan henüz geri bildirim almadı", "This clause has no contract creation": "Bu maddede sözleşme oluşturulmamış", "This page does not exist": "Bu sayfa mevcut değil", "This transaction has no events": "Bu işlemin hiçbir olayı yok", @@ -261,6 +301,7 @@ "Total Clauses": "Toplam Kloz", "Total Earned": "Toplam Kazanç", "Total EUR": "Toplam EUR", + "Total Feedback": "Toplam Geri Bildirim", "Total Fees Paid": "Ödenen Toplam Ücretler", "Total Gas Used": "Toplam Kullanılan Gas", "Total Holders": "Toplam Sahipler", @@ -288,6 +329,7 @@ "Tx ID": "İşlem Kimliği", "Txs/Clauses": "Tx'ler/Klozlar", "Type": "Tür", + "Unique Clients": "Benzersiz İstemciler", "Unknown": "Bilinmeyen", "Usage": "Kullanım", "USD": "USD", @@ -300,6 +342,7 @@ "Validators": "Doğrulayıcılar", "Value": "Değer", "VeChain": "VeChain", + "Version": "Sürüm", "VET": "VET", "VET Balance": "VET Bakiyesi", "VET Price": "VET Fiyatı", diff --git a/i18n/languages/zh.json b/i18n/languages/zh.json index 47ad1e7f..7cfbb504 100644 --- a/i18n/languages/zh.json +++ b/i18n/languages/zh.json @@ -2,6 +2,7 @@ "1D": "1天", "1M": "1个月", "1Y": "1年", + "A2A Agent Card": "A2A 智能体卡片", "Account": "账户", "Active": "活跃", "Active Stake": "Active Stake", @@ -11,12 +12,18 @@ "AFPT": "AFPT", "AFPU": "AFPU", "Age": "区块龄", + "Agent": "智能体", + "Agent ID": "智能体 ID", + "Agent Overview": "智能体概览", + "Agent Registry": "智能体注册表", + "AI Agent": "AI 智能体", "All": "全部", "All Time": "所有时间", "Amount": "数量", "Attributes": "属性", "Average Fees Per Transaction (AFPT)": "Average Fees Per Transaction (AFPT)", "Average Fees Per User (AFPU)": "每用户平均费用 (AFPU)", + "Average Rating": "平均评分", "Avg AFPT": "Avg AFPT", "Avg AFPU": "平均AFPU", "Avg Gas Limit/Block": "每区块平均 Gas 限额", @@ -54,6 +61,7 @@ "Clause #{{index}} with selector {{selector}} reverted immediately without a decoded reason. This often means the calldata was encoded with an outdated ABI or wrong function signature.": "带有选择器 {{selector}} 的子句 #{{index}} 在没有可解码原因的情况下立即回退。这通常意味着 calldata 是用过期的 ABI 或错误的函数签名编码的。", "Clause details": "子交易详情", "Clauses": "条款", + "Client": "客户端", "Close navigation menu": "Close navigation menu", "Co2e": "二氧化碳当量", "CO2e emitted": "排放的CO2e", @@ -73,6 +81,7 @@ "Created contract address": "已创建合约地址", "Created On": "创建时间", "Creation Transaction": "创建交易", + "Creator": "创建者", "Cycle duration": "周期时长", "Cycle left": "剩余周期", "Daily": "每日", @@ -81,6 +90,7 @@ "Date": "日期", "Date & Time": "日期和时间", "Date time": "日期时间", + "Deactivated": "已停用", "Decode": "解码", "Decoded": "解码后", "decoded": "已解码", @@ -96,10 +106,13 @@ "details": "详情", "Dev mode": "开发模式", "DEX Trades": "DEX Trades", + "Disabled": "已禁用", "Earned Rewards": "已获得奖励", "emitter": "发送者", + "Enabled": "已启用", "Endorsed validators": "已背书的验证者", "Endorser": "背书人", + "Endpoint": "端点", "Enter a valid URL": "请输入有效的 URL", "Events": "事件", "events": "事件", @@ -111,6 +124,7 @@ "Fee": "手续费", "Fee delegated to": "费用委托给", "Fee Paid": "已支付手续费", + "Feedback": "反馈", "Fees, Gas and VTHO": "手续费、Gas 和 VTHO", "Finalized": "已最终确认", "Finalizing": "最终确认中", @@ -136,6 +150,7 @@ "indexed": "已索引", "Indexer URL must not include /api or /v": "索引器 URL 不能包含 /api 或 /v", "Input data": "输入数据", + "Input Modes": "输入模式", "input-data": "输入数据", "Inspect tool": "检查工具", "Last page": "最后一页", @@ -145,6 +160,7 @@ "Market Cap": "市值", "Marketplace": "市场", "Max Fee per Gas": "每Gas最高费用", + "Metadata": "元数据", "Metadata not found at this uri": "在此URI未找到元数据", "Metrics": "指标", "Mint": "铸造", @@ -171,8 +187,13 @@ "No contract creation": "无合约创建", "No contracts": "没有合约", "No events": "无事件", + "No feedback available": "暂无反馈", + "No feedback yet": "暂无反馈", "No image": "暂无图片", "No NFTs": "暂无NFT", + "No quality data available": "暂无质量数据", + "No services listed": "未列出服务", + "No statistics available": "暂无统计数据", "No token transfers": "无代币转账", "No token transfers have been recorded yet": "尚未记录代币转账", "No tokens": "无代币", @@ -183,9 +204,12 @@ "Not delegated": "未委托", "Now": "现在", "of": "的", + "On-chain Identity": "链上身份", "Oops! Something went wrong": "哎呀!出现了问题", "Open navigation menu": "Open navigation menu", "Origin": "来源", + "Output Modes": "输出模式", + "Overview": "概览", "Owned by": "拥有者", "Owned Contracts": "已拥有的合约", "Page": "页面", @@ -199,37 +223,50 @@ "Price": "价格", "Priority Fee per Gas": "每Gas优先费用", "Privacy Policy": "隐私政策", + "Quality": "质量", + "Rating": "评分", "Raw": "原始", "raw": "原始", + "Raw Metadata": "原始元数据", + "Registered": "注册时间", "Reliability": "可靠性", + "Reputation Registry": "信誉注册表", "Reset": "重置", "Resources": "资源", "Revert Reason": "回退原因", "Reverted": "已还原", + "Revoked": "已撤销", "Rewards": "奖励", "Rows": "行数", "Rows per page": "每页行数", "Sale": "销售", "Save": "保存", + "Schema": "模式", "Search": "Search", "Search for blocks, transactions or accounts": "搜索区块、交易或账户", "Select Currency": "选择货币", "Select Language": "选择语言", + "Services": "服务", "Show": "显示", "Show All": "显示全部", "Show Less": "显示较少", "Signer": "签名者", "Size": "大小", + "Skills": "技能", "Solo indexer URL": "Solo 索引器 URL", "Solo node URL": "Solo 节点 URL", "Something went wrong 😬": "出现错误 😬", "Staking NFTs": "staking NFT", "Stargate": "Stargate", "StarGate Docs": "StarGate 文档", + "Statistics": "统计", "Status": "状态", + "Streaming": "流式传输", "success": "成功", "Support": "支持", "Support Center": "支持中心", + "Supported Trust": "支持的信任模型", + "Suspended": "已暂停", "Symbol": "代号", "Terms of Service": "服务条款", "Testnet": "Testnet", @@ -242,6 +279,9 @@ "This account has not deployed any contracts yet": "该账号尚未部署任何合约", "This account has not made any transactions yet": "该账户尚未进行任何交易", "This account has not made any transfers yet": "该账户尚未进行任何转账", + "This agent does not publish an on-chain reputation registry": "该智能体未发布链上信誉注册表", + "This agent has not advertised any services yet": "该智能体尚未公布任何服务", + "This agent has not received any feedback yet": "该智能体尚未收到任何反馈", "This clause has no contract creation": "此子条款没有合约创建", "This page does not exist": "该页面不存在", "This transaction has no events": "此交易没有事件", @@ -261,6 +301,7 @@ "Total Clauses": "总条款数", "Total Earned": "累计收益", "Total EUR": "总计欧元", + "Total Feedback": "反馈总数", "Total Fees Paid": "已支付总费用", "Total Gas Used": "总Gas使用量", "Total Holders": "持有者总数", @@ -288,6 +329,7 @@ "Tx ID": "交易编号", "Txs/Clauses": "交易/条款", "Type": "类型", + "Unique Clients": "独立客户端", "Unknown": "未知", "Usage": "用量", "USD": "美元", @@ -300,6 +342,7 @@ "Validators": "验证者", "Value": "数值", "VeChain": "VeChain", + "Version": "版本", "VET": "VET", "VET Balance": "VET余额", "VET Price": "VET价格", diff --git a/services/agent-nft/hooks.ts b/services/agent-nft/hooks.ts new file mode 100644 index 00000000..80430799 --- /dev/null +++ b/services/agent-nft/hooks.ts @@ -0,0 +1,58 @@ +import { useQuery } from '@tanstack/react-query' +import { apiClient } from '@/lib/api' +import { parseNftMetadataUri } from '@/services/nft-metadata' +import { type AgentCard, agentCardSchema, type AgentRegistration, agentRegistrationSchema } from './schemas' + +const AGENT_REGISTRATION_QUERY_KEY = 'getAgentRegistration' +const AGENT_CARD_QUERY_KEY = 'getAgentCard' + +/** Fetch any JSON document through the server-side `/api/nft-metadata` proxy (avoids CORS). */ +const fetchJsonViaProxy = async (uri: string): Promise => { + const { data } = await apiClient.get({ + baseUrl: '/api', + endPoint: '/nft-metadata', + params: { uri: encodeURIComponent(uri) }, + }) + return data +} + +/** + * Fetch and parse an NFT's `tokenURI` JSON as an agent registration file. + * Returns `null` for any NFT whose metadata is not an agent registration file, + * so callers can branch on the result without throwing. + */ +const getAgentRegistration = async (uri: string): Promise => { + const result = agentRegistrationSchema.safeParse(await fetchJsonViaProxy(uri)) + return result.success ? result.data : null +} + +export const useAgentRegistration = ({ tokenUri }: { tokenUri: string | null | undefined }) => { + const parsedUri = tokenUri ? parseNftMetadataUri(tokenUri) : '' + + return useQuery({ + queryKey: [AGENT_REGISTRATION_QUERY_KEY, parsedUri], + queryFn: () => getAgentRegistration(parsedUri), + enabled: !!parsedUri, + staleTime: Infinity, + }) +} + +/** + * Fetch the A2A AgentCard from the registration file's `A2A` service endpoint. + * Returns `null` when the document does not parse as an AgentCard. + */ +const getAgentCard = async (endpoint: string): Promise => { + const result = agentCardSchema.safeParse(await fetchJsonViaProxy(endpoint)) + return result.success ? result.data : null +} + +export const useAgentCard = ({ endpoint }: { endpoint: string | null | undefined }) => { + const parsedEndpoint = endpoint ? parseNftMetadataUri(endpoint) : '' + + return useQuery({ + queryKey: [AGENT_CARD_QUERY_KEY, parsedEndpoint], + queryFn: () => getAgentCard(parsedEndpoint), + enabled: !!parsedEndpoint, + staleTime: Infinity, + }) +} diff --git a/services/agent-nft/schemas.spec.ts b/services/agent-nft/schemas.spec.ts new file mode 100644 index 00000000..91c2e7fc --- /dev/null +++ b/services/agent-nft/schemas.spec.ts @@ -0,0 +1,125 @@ +import { describe, expect, it } from 'vitest' +import { + AGENT_REGISTRATION_TYPE, + agentCardSchema, + agentRegistrationSchema, + getAgentCardEndpoint, + isAgentRegistration, + parseCaipAddress, +} from './schemas' + +// Real ERC-8004 registration file shape served at an agent NFT's tokenURI. +const registrationFixture = { + type: AGENT_REGISTRATION_TYPE, + name: 'Atelier Agent', + description: 'Shape your agent’s identity, role, and voice.', + image: 'http://localhost:3001/api/agents/2e991bd5/avatar?v=7570dcf1.jpg', + services: [ + { name: 'web', endpoint: 'http://localhost:3000/agents/2e991bd5' }, + { name: 'A2A', endpoint: 'http://localhost:3001/api/agents/onchain/2/agent-card.json', version: '0.3.0' }, + ], + x402Support: false, + active: true, + registrations: [{ agentId: 2, agentRegistry: 'eip155:100010:0x271eb84c5095db823d76f87e10bb19016b117073' }], + supportedTrust: ['reputation'], + reputationRegistry: { chainId: 100010, address: '0x654ea4792c34b518970f1b28dbce1d10f0562ae7' }, +} + +const agentCardFixture = { + name: 'Atelier Agent', + description: 'Shape your agent’s identity, role, and voice.', + url: 'http://localhost:3000/agents/2e991bd5', + version: '1', + capabilities: { streaming: true }, + defaultInputModes: ['text/plain'], + defaultOutputModes: ['text/plain'], + skills: [{ id: 'c42b72a8', name: 'skill-1', description: 'Summarize emails' }], +} + +// A plain ERC-721 metadata blob (no agent markers). +const plainNftMetadata = { + name: 'Cool Cat #1', + description: 'A cool cat', + image: 'ipfs://Qm.../1.png', + attributes: [{ trait_type: 'Background', value: 'Blue' }], +} + +describe('isAgentRegistration', () => { + it('recognises an agent registration file by its `type` marker', () => { + expect(isAgentRegistration(registrationFixture)).toBe(true) + }) + + it('rejects a plain NFT metadata blob', () => { + expect(isAgentRegistration(plainNftMetadata)).toBe(false) + }) + + it('rejects a registration file with the wrong `type` marker', () => { + expect(isAgentRegistration({ ...registrationFixture, type: 'something/else' })).toBe(false) + }) + + it('rejects null / non-objects', () => { + expect(isAgentRegistration(null)).toBe(false) + expect(isAgentRegistration('nope')).toBe(false) + }) +}) + +describe('agentRegistrationSchema', () => { + it('parses the fixture and exposes agent fields', () => { + const parsed = agentRegistrationSchema.parse(registrationFixture) + expect(parsed.name).toBe('Atelier Agent') + expect(parsed.registrations[0]?.agentId).toBe(2) + expect(parsed.reputationRegistry?.address).toBe('0x654ea4792c34b518970f1b28dbce1d10f0562ae7') + expect(parsed.reputationRegistry?.chainId).toBe(100010) + expect(parsed.services).toHaveLength(2) + expect(parsed.active).toBe(true) + }) + + it('defaults optional fields on a minimal registration file', () => { + const parsed = agentRegistrationSchema.parse({ type: AGENT_REGISTRATION_TYPE }) + expect(parsed.services).toEqual([]) + expect(parsed.supportedTrust).toEqual([]) + expect(parsed.reputationRegistry).toBeNull() + expect(parsed.x402Support).toBe(false) + expect(parsed.active).toBe(true) + }) +}) + +describe('getAgentCardEndpoint', () => { + it('returns the A2A service endpoint', () => { + const parsed = agentRegistrationSchema.parse(registrationFixture) + expect(getAgentCardEndpoint(parsed)).toBe('http://localhost:3001/api/agents/onchain/2/agent-card.json') + }) + + it('returns undefined when there is no A2A service', () => { + const parsed = agentRegistrationSchema.parse({ + type: AGENT_REGISTRATION_TYPE, + services: [{ name: 'web', endpoint: 'https://example.com' }], + }) + expect(getAgentCardEndpoint(parsed)).toBeUndefined() + }) +}) + +describe('parseCaipAddress', () => { + it('extracts the address from a CAIP-10 reference', () => { + expect(parseCaipAddress('eip155:100010:0x271eb84c5095db823d76f87e10bb19016b117073')).toBe( + '0x271eb84c5095db823d76f87e10bb19016b117073', + ) + }) + + it('accepts a bare address and rejects junk', () => { + expect(parseCaipAddress('0x271eb84c5095db823d76f87e10bb19016b117073')).toBe( + '0x271eb84c5095db823d76f87e10bb19016b117073', + ) + expect(parseCaipAddress('eip155:100010:not-an-address')).toBeNull() + expect(parseCaipAddress(undefined)).toBeNull() + }) +}) + +describe('agentCardSchema', () => { + it('parses the A2A card fixture', () => { + const parsed = agentCardSchema.parse(agentCardFixture) + expect(parsed.capabilities.streaming).toBe(true) + expect(parsed.skills[0]?.name).toBe('skill-1') + expect(parsed.defaultInputModes).toEqual(['text/plain']) + }) +}) diff --git a/services/agent-nft/schemas.ts b/services/agent-nft/schemas.ts new file mode 100644 index 00000000..5d4be99d --- /dev/null +++ b/services/agent-nft/schemas.ts @@ -0,0 +1,96 @@ +import z from 'zod' +import { addressStringSchema, type AddressString } from '@/lib/schemas' + +/** + * `type` marker written into the on-chain `tokenURI` JSON by the VeChain agent + * marketplace. Its presence is how the explorer recognises that an NFT is an + * agent NFT (an ERC-8004 registration file) rather than a plain collectible. + * Source: agent-marketplace `apps/backend/src/agents/registration-file.ts`. + */ +export const AGENT_REGISTRATION_TYPE = 'https://eips.ethereum.org/EIPS/eip-8004#registration-v1' + +/** One advertised endpoint in the registration file's `services` array. */ +const registrationServiceSchema = z.object({ + name: z.string().default(''), + endpoint: z.string().default(''), + version: z.string().optional(), +}) + +/** + * The ERC-8004 registration file served at an agent NFT's `tokenURI`. Only the + * `type` marker is required — every other field is defaulted so a slightly + * different registration file still parses. A plain-NFT metadata blob lacks the + * `type` marker and fails the parse (see {@link isAgentRegistration}). + */ +export const agentRegistrationSchema = z.object({ + type: z.literal(AGENT_REGISTRATION_TYPE), + name: z.string().default(''), + description: z.string().nullable().default(null), + image: z.string().nullable().default(null), + services: z.array(registrationServiceSchema).default([]), + x402Support: z.boolean().default(false), + active: z.boolean().default(true), + registrations: z + .array( + z.object({ + agentId: z.number(), + // CAIP-10 style reference, e.g. `eip155:100010:0x271eb84c...`. + agentRegistry: z.string(), + }), + ) + .default([]), + supportedTrust: z.array(z.string()).default([]), + reputationRegistry: z + .object({ + chainId: z.number(), + address: addressStringSchema, + }) + .nullable() + .default(null), +}) + +/** + * The A2A AgentCard — a separate document fetched from the registration file's + * `A2A` service endpoint (`.../agent-card.json`). Skills live here, NOT in the + * registration file's `services`. + */ +export const agentCardSchema = z.object({ + name: z.string().default(''), + description: z.string().nullable().default(null), + url: z.string().default(''), + version: z.string().default(''), + capabilities: z.object({ streaming: z.boolean().default(false) }).default({ streaming: false }), + defaultInputModes: z.array(z.string()).default([]), + defaultOutputModes: z.array(z.string()).default([]), + skills: z + .array( + z.object({ + id: z.string().default(''), + name: z.string().default(''), + description: z.string().nullable().default(null), + }), + ) + .default([]), +}) + +export type AgentRegistration = z.infer +export type AgentCard = z.infer + +/** True when `data` is a parseable agent-marketplace ERC-8004 registration file. */ +export const isAgentRegistration = (data: unknown): data is AgentRegistration => + agentRegistrationSchema.safeParse(data).success + +/** The endpoint of the `A2A` service entry, if the agent advertises one. */ +export const getAgentCardEndpoint = (registration: AgentRegistration): string | undefined => + registration.services.find(service => service.name.toUpperCase() === 'A2A')?.endpoint || undefined + +/** + * Pull the plain address out of a CAIP-10 `eip155::
` reference. + * Returns null when the reference does not contain a valid address. + */ +export const parseCaipAddress = (reference: string | undefined): AddressString | null => { + if (!reference) return null + const candidate = reference.includes(':') ? reference.split(':').pop() : reference + const result = addressStringSchema.safeParse(candidate) + return result.success ? result.data : null +} diff --git a/services/thor/tokens/agent-registry.ts b/services/thor/tokens/agent-registry.ts new file mode 100644 index 00000000..365af787 --- /dev/null +++ b/services/thor/tokens/agent-registry.ts @@ -0,0 +1,72 @@ +import { useQuery } from '@tanstack/react-query' +import type { NetworkName } from '@/lib/constants/network' +import type { AddressString } from '@/lib/schemas' +import { useSettingsStore } from '@/lib/stores/settings' +import { getThorClient } from '@/services/thor/client' + +const AGENT_INFO_QUERY_KEY = 'getAgentInfo' + +// ABI fragment for the agent-marketplace AgentRegistry `getAgent` view. +const AGENT_REGISTRY_ABI = [ + { + inputs: [{ internalType: 'uint256', name: 'agentId', type: 'uint256' }], + name: 'getAgent', + outputs: [ + { + components: [ + { internalType: 'address', name: 'creator', type: 'address' }, + { internalType: 'uint64', name: 'registeredAt', type: 'uint64' }, + { internalType: 'bool', name: 'suspended', type: 'bool' }, + { internalType: 'bool', name: 'deactivated', type: 'bool' }, + ], + internalType: 'struct IAgentRegistry.AgentInfo', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const + +export interface AgentInfo { + creator: AddressString + /** Registration timestamp in milliseconds. */ + registeredAt: number + suspended: boolean + deactivated: boolean +} + +const getAgentInfo = async ( + networkName: NetworkName, + contractAddress: AddressString, + agentId: bigint, +): Promise => { + try { + const thorClient = getThorClient(networkName) + const contract = thorClient.contracts.load(contractAddress, AGENT_REGISTRY_ABI) + const [info] = await contract.read.getAgent(agentId) + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const agent = info as any + return { + creator: (agent.creator ?? agent[0]) as AddressString, + registeredAt: Number(agent.registeredAt ?? agent[1]) * 1000, + suspended: Boolean(agent.suspended ?? agent[2]), + deactivated: Boolean(agent.deactivated ?? agent[3]), + } + } catch (error) { + console.error('Error fetching agent info:', error) + return null + } +} + +export const useAgentInfo = ({ contractAddress, agentId }: { contractAddress: AddressString; agentId: bigint }) => { + const { activeNetwork } = useSettingsStore() + + return useQuery({ + queryKey: [AGENT_INFO_QUERY_KEY, activeNetwork.name, contractAddress, agentId.toString()], + queryFn: () => getAgentInfo(activeNetwork.name, contractAddress, agentId), + staleTime: 60_000, + }) +} diff --git a/services/thor/tokens/reputation-registry.ts b/services/thor/tokens/reputation-registry.ts new file mode 100644 index 00000000..19a47e2f --- /dev/null +++ b/services/thor/tokens/reputation-registry.ts @@ -0,0 +1,145 @@ +import { useQuery } from '@tanstack/react-query' +import type { NetworkName } from '@/lib/constants/network' +import type { AddressString } from '@/lib/schemas' +import { useSettingsStore } from '@/lib/stores/settings' +import { getThorClient } from '@/services/thor/client' + +const AGENT_REPUTATION_QUERY_KEY = 'getAgentReputation' + +// ABI fragments for the agent-marketplace ERC-8004 ReputationRegistry reads. +const REPUTATION_REGISTRY_ABI = [ + { + inputs: [{ internalType: 'uint256', name: 'agentId', type: 'uint256' }], + name: 'getClients', + outputs: [{ internalType: 'address[]', name: '', type: 'address[]' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'agentId', type: 'uint256' }, + { internalType: 'address[]', name: 'clientAddresses', type: 'address[]' }, + { internalType: 'string', name: 'tag1', type: 'string' }, + { internalType: 'string', name: 'tag2', type: 'string' }, + ], + name: 'getSummary', + outputs: [ + { internalType: 'uint64', name: 'count', type: 'uint64' }, + { internalType: 'int256', name: 'summaryValue', type: 'int256' }, + { internalType: 'uint8', name: 'summaryValueDecimals', type: 'uint8' }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'agentId', type: 'uint256' }, + { internalType: 'address[]', name: 'clientAddresses', type: 'address[]' }, + { internalType: 'string', name: 'tag1', type: 'string' }, + { internalType: 'string', name: 'tag2', type: 'string' }, + { internalType: 'bool', name: 'includeRevoked', type: 'bool' }, + ], + name: 'readAllFeedback', + outputs: [ + { internalType: 'address[]', name: 'clients', type: 'address[]' }, + { internalType: 'uint64[]', name: 'feedbackIndexes', type: 'uint64[]' }, + { internalType: 'int128[]', name: 'feedbackValues', type: 'int128[]' }, + { internalType: 'uint8[]', name: 'valueDecimalsList', type: 'uint8[]' }, + { internalType: 'bool[]', name: 'revokedStatuses', type: 'bool[]' }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const + +interface AgentFeedbackEntry { + client: AddressString + index: number + /** Feedback value normalised by its on-chain `valueDecimals`. */ + value: number + revoked: boolean +} + +export interface AgentReputation { + /** Total non-revoked feedback entries. */ + feedbackCount: number + /** Distinct clients that have left feedback. */ + clientCount: number + /** Mean feedback value (sum / count) normalised by decimals, or null when empty. */ + averageValue: number | null + feedback: AgentFeedbackEntry[] +} + +const EMPTY_REPUTATION: AgentReputation = { + feedbackCount: 0, + clientCount: 0, + averageValue: null, + feedback: [], +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const toArray = (value: any): any[] => (Array.isArray(value) ? value : []) + +const getAgentReputation = async ( + networkName: NetworkName, + reputationAddress: AddressString, + agentId: bigint, +): Promise => { + try { + const thorClient = getThorClient(networkName) + const contract = thorClient.contracts.load(reputationAddress, REPUTATION_REGISTRY_ABI) + + const [rawClients] = await contract.read.getClients(agentId) + const clients = toArray(rawClients) as AddressString[] + if (clients.length === 0) return EMPTY_REPUTATION + + const [count, summaryValue, summaryValueDecimals] = await contract.read.getSummary(agentId, clients, '', '') + const [feedbackClients, feedbackIndexes, feedbackValues, valueDecimalsList, revokedStatuses] = + await contract.read.readAllFeedback(agentId, clients, '', '', false) + + const decimals = Number(summaryValueDecimals ?? 0) + const feedbackCount = Number(count ?? 0) + const sum = Number(summaryValue ?? 0) / 10 ** decimals + const averageValue = feedbackCount > 0 ? sum / feedbackCount : null + + const fbClients = toArray(feedbackClients) + const fbIndexes = toArray(feedbackIndexes) + const fbValues = toArray(feedbackValues) + const fbDecimals = toArray(valueDecimalsList) + const fbRevoked = toArray(revokedStatuses) + + const feedback: AgentFeedbackEntry[] = fbClients.map((client, i) => ({ + client: client as AddressString, + index: Number(fbIndexes[i] ?? 0), + value: Number(fbValues[i] ?? 0) / 10 ** Number(fbDecimals[i] ?? 0), + revoked: Boolean(fbRevoked[i]), + })) + + return { + feedbackCount, + clientCount: clients.length, + averageValue, + feedback, + } + } catch (error) { + console.error('Error fetching agent reputation:', error) + return EMPTY_REPUTATION + } +} + +export const useAgentReputation = ({ + reputationAddress, + agentId, +}: { + reputationAddress: AddressString | null | undefined + agentId: bigint +}) => { + const { activeNetwork } = useSettingsStore() + + return useQuery({ + queryKey: [AGENT_REPUTATION_QUERY_KEY, activeNetwork.name, reputationAddress ?? '', agentId.toString()], + queryFn: () => getAgentReputation(activeNetwork.name, reputationAddress as AddressString, agentId), + enabled: !!reputationAddress, + staleTime: 60_000, + }) +}