diff --git a/apps/explorer/src/components/ui/InternalLink.tsx b/apps/explorer/src/components/ui/InternalLink.tsx index 22dfe4d4ee5..64ec36a573a 100644 --- a/apps/explorer/src/components/ui/InternalLink.tsx +++ b/apps/explorer/src/components/ui/InternalLink.tsx @@ -2,7 +2,7 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { formatAddress, formatDigest } from '@iota/iota-sdk/utils'; +import { formatAddress, formatDigest, formatType } from '@iota/iota-sdk/utils'; import { type ReactNode } from 'react'; import { Link, type LinkProps } from '~/components/ui'; @@ -48,6 +48,6 @@ export const CheckpointSequenceLink = createInternalLink('checkpoint', 'sequence export const AddressLink = createInternalLink('address', 'address', (addressOrNs) => formatAddress(addressOrNs), ); -export const ObjectLink = createInternalLink('object', 'objectId', formatAddress); +export const ObjectLink = createInternalLink('object', 'objectId', formatType); export const TransactionLink = createInternalLink('txblock', 'digest', formatDigest); export const ValidatorLink = createInternalLink('validator', 'address', formatAddress); diff --git a/apps/explorer/src/lib/ui/utils/generateObjectListColumns.tsx b/apps/explorer/src/lib/ui/utils/generateObjectListColumns.tsx index 223f4c35305..6debf9d9cc0 100644 --- a/apps/explorer/src/lib/ui/utils/generateObjectListColumns.tsx +++ b/apps/explorer/src/lib/ui/utils/generateObjectListColumns.tsx @@ -4,11 +4,11 @@ import { TableCellBase, TableCellText } from '@iota/apps-ui-kit'; import type { ColumnDef } from '@tanstack/react-table'; -import { parseObjectType, trimStdLibPrefix } from '~/lib'; -import { ObjectVideoImage, ObjectLink } from '~/components'; import type { IotaObjectResponse } from '@iota/iota-sdk/client'; +import { formatAddress, formatType } from '@iota/iota-sdk/utils'; +import { ObjectLink, ObjectVideoImage } from '~/components'; import { useResolveVideo } from '~/hooks'; -import { formatAddress } from '@iota/iota-sdk/utils'; +import { parseObjectType, trimStdLibPrefix } from '~/lib'; function Asset({ object }: { object: IotaObjectResponse }) { const video = useResolveVideo(object); @@ -56,7 +56,7 @@ export function generateObjectListColumns(): ColumnDef[] { cell({ row: { original: object } }) { const objectId = object?.data?.objectId; if (!objectId) return null; - const type = trimStdLibPrefix(parseObjectType(object)); + const type = formatType(trimStdLibPrefix(parseObjectType(object))); return ( diff --git a/apps/explorer/src/lib/ui/utils/generateTransactionsTableColumns.tsx b/apps/explorer/src/lib/ui/utils/generateTransactionsTableColumns.tsx index 09f3954bc5f..3cc12a45e2a 100644 --- a/apps/explorer/src/lib/ui/utils/generateTransactionsTableColumns.tsx +++ b/apps/explorer/src/lib/ui/utils/generateTransactionsTableColumns.tsx @@ -8,7 +8,7 @@ import type { IotaTransactionBlockKind, IotaTransactionBlockResponse } from '@io import { TableCellBase, TableCellText } from '@iota/apps-ui-kit'; import type { ColumnDef } from '@tanstack/react-table'; import { AddressLink, TransactionLink } from '../../../components/ui'; -import { formatAddress, NANOS_PER_IOTA } from '@iota/iota-sdk/utils'; +import { formatAddress, formatDigest, NANOS_PER_IOTA } from '@iota/iota-sdk/utils'; import { getElapsedTime } from '~/pages/epochs/utils'; /** @@ -25,7 +25,7 @@ export function generateTransactionsTableColumns(): ColumnDef {formatAddress(digest)}} + label={{formatDigest(digest)}} /> ); diff --git a/apps/explorer/src/pages/object-result/views/ObjectView.tsx b/apps/explorer/src/pages/object-result/views/ObjectView.tsx index 57003094f59..d9c4f427ebc 100644 --- a/apps/explorer/src/pages/object-result/views/ObjectView.tsx +++ b/apps/explorer/src/pages/object-result/views/ObjectView.tsx @@ -7,6 +7,7 @@ import { CoinFormat, useFormatCoin } from '@iota/core'; import { type IotaObjectResponse, type ObjectOwner } from '@iota/iota-sdk/client'; import { formatAddress, + formatDigest, IOTA_TYPE_ARG, normalizeStructTag, parseStructTag, @@ -113,12 +114,11 @@ function TypeCard({ objectType }: TypeCardCardProps): JSX.Element { }; const normalizedStructTag = normalizeStructTag(structTag); - return ( + {normalizedStructTag} } @@ -144,7 +144,7 @@ function LastTxBlockCard({ digest }: LastTxBlockCardProps): JSX.Element { return ( {formatAddress(digest)}} + value={{formatDigest(digest)}} /> ); } diff --git a/sdk/typescript/src/utils/format.ts b/sdk/typescript/src/utils/format.ts index 1648cf629cb..8f54589df70 100644 --- a/sdk/typescript/src/utils/format.ts +++ b/sdk/typescript/src/utils/format.ts @@ -2,6 +2,8 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +import { isValidIotaAddress, isValidIotaObjectId, IOTA_ADDRESS_LENGTH } from './iota-types.js'; + const ELLIPSIS = '\u{2026}'; export function formatAddress(address: string) { @@ -18,3 +20,14 @@ export function formatDigest(digest: string) { // Use 10 first characters return `${digest.slice(0, 10)}${ELLIPSIS}`; } + +export function formatType(type: string) { + const objectAddressPattern = new RegExp(`0x[a-fA-F0-9]{${IOTA_ADDRESS_LENGTH * 2}}`, 'g'); + const matches = type.match(objectAddressPattern) ?? []; + for (const match of matches) { + if (isValidIotaAddress(match) || isValidIotaObjectId(match)) { + type = type.replace(match, formatAddress(match)); + } + } + return type; +} diff --git a/sdk/typescript/src/utils/index.ts b/sdk/typescript/src/utils/index.ts index 231636ad254..3f579b43063 100644 --- a/sdk/typescript/src/utils/index.ts +++ b/sdk/typescript/src/utils/index.ts @@ -2,7 +2,7 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -export { formatAddress, formatDigest } from './format.js'; +export { formatAddress, formatDigest, formatType } from './format.js'; export { isValidIotaAddress, isValidIotaObjectId, diff --git a/sdk/typescript/test/unit/format.test.ts b/sdk/typescript/test/unit/format.test.ts new file mode 100644 index 00000000000..9c4197d06f5 --- /dev/null +++ b/sdk/typescript/test/unit/format.test.ts @@ -0,0 +1,19 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, it } from 'vitest'; +import { formatType } from '../../src/utils'; + +describe('Formatters', () => { + it('formatType formats correctly', async () => { + const typeClock = '0x2::clock::Clock'; + expect(formatType(typeClock), '0x0000…0002::clock::Clock'); + + const typeCoolCoin = + '0x2::coin::Coin<0x2e0b8d1e74947a2d97121bc7b7981eaff1f32911d15c5e0921fdd08cf61f445b::cool_coin::COOL_COIN>'; + expect( + formatType(typeCoolCoin), + '0x0000…0002::coin::Coin', + ); + }); +});