diff --git a/mocks/address/address.ts b/mocks/address/address.ts index e58097c2f5..112f774ba0 100644 --- a/mocks/address/address.ts +++ b/mocks/address/address.ts @@ -157,3 +157,12 @@ export const validator: Address = { watchlist_address_id: null, ens_domain_name: null, }; + +export const filecoin = { + ...validator, + filecoin: { + actor_type: 'evm' as const, + id: 'f02977693', + robust: 'f410fuiwj6a3yxajbohrl5vu6ns6o2e2jriul52lvzci', + }, +}; diff --git a/types/api/address.ts b/types/api/address.ts index 733350cc93..3d38e65d86 100644 --- a/types/api/address.ts +++ b/types/api/address.ts @@ -14,6 +14,7 @@ export interface Address extends UserTags { creation_tx_hash: string | null; exchange_rate: string | null; ens_domain_name: string | null; + filecoin?: AddressFilecoinParams; // TODO: if we are happy with tabs-counters method, should we delete has_something fields? has_beacon_chain_withdrawals?: boolean; has_decompiled_code: boolean; @@ -268,3 +269,27 @@ export type AddressEpochRewardsItem = { epoch_number: number; associated_account: AddressParam; } + +export type AddressFilecoinParams = { + actor_type: FilecoinActorType; + id: string; + robust: string; +} + +export type FilecoinActorType = + 'account' | + 'cron' | + 'datacap' | + 'eam' | + 'ethaccount' | + 'evm' | + 'init' | + 'market' | + 'miner' | + 'multisig' | + 'paych' | + 'placeholder' | + 'power' | + 'reward' | + 'system' | + 'verifreg'; diff --git a/types/api/addressParams.ts b/types/api/addressParams.ts index 069302e808..4b82507154 100644 --- a/types/api/addressParams.ts +++ b/types/api/addressParams.ts @@ -1,3 +1,4 @@ +import type { AddressFilecoinParams } from './address'; import type { AddressMetadataTagApi } from './addressMetadata'; export interface AddressImplementation { @@ -33,6 +34,7 @@ export type AddressParamBasic = { reputation: number | null; tags: Array; } | null; + filecoin?: AddressFilecoinParams; } export type AddressParam = UserTags & AddressParamBasic; diff --git a/ui/address/AddressDetails.pw.tsx b/ui/address/AddressDetails.pw.tsx index 7d49ae723d..9c7a14917d 100644 --- a/ui/address/AddressDetails.pw.tsx +++ b/ui/address/AddressDetails.pw.tsx @@ -44,6 +44,17 @@ test.describe('mobile', () => { }); }); + test('filecoin', async({ render, mockApiResponse, page }) => { + await mockApiResponse('address', addressMock.filecoin, { pathParams: { hash: ADDRESS_HASH } }); + await mockApiResponse('address_counters', countersMock.forValidator, { pathParams: { hash: ADDRESS_HASH } }); + + const component = await render(, { hooksConfig }); + + await expect(component).toHaveScreenshot({ + mask: [ page.locator(pwConfig.adsBannerSelector) ], + maskColor: pwConfig.maskColor, + }); + }); }); test('contract', async({ render, page, mockApiResponse }) => { @@ -92,3 +103,15 @@ test('validator', async({ render, mockApiResponse, page }) => { maskColor: pwConfig.maskColor, }); }); + +test('filecoin', async({ render, mockApiResponse, page }) => { + await mockApiResponse('address', addressMock.filecoin, { pathParams: { hash: ADDRESS_HASH } }); + await mockApiResponse('address_counters', countersMock.forValidator, { pathParams: { hash: ADDRESS_HASH } }); + + const component = await render(, { hooksConfig }); + + await expect(component).toHaveScreenshot({ + mask: [ page.locator(pwConfig.adsBannerSelector) ], + maskColor: pwConfig.maskColor, + }); +}); diff --git a/ui/address/AddressDetails.tsx b/ui/address/AddressDetails.tsx index e781f5b519..47d0a7dec3 100644 --- a/ui/address/AddressDetails.tsx +++ b/ui/address/AddressDetails.tsx @@ -10,18 +10,21 @@ import getQueryParamString from 'lib/router/getQueryParamString'; import AddressCounterItem from 'ui/address/details/AddressCounterItem'; import ServiceDegradationWarning from 'ui/shared/alerts/ServiceDegradationWarning'; import isCustomAppError from 'ui/shared/AppError/isCustomAppError'; +import CopyToClipboard from 'ui/shared/CopyToClipboard'; import DataFetchAlert from 'ui/shared/DataFetchAlert'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem'; import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import BlockEntity from 'ui/shared/entities/block/BlockEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity'; +import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import AddressBalance from './details/AddressBalance'; import AddressImplementations from './details/AddressImplementations'; import AddressNameInfo from './details/AddressNameInfo'; import AddressNetWorth from './details/AddressNetWorth'; import AddressSaveOnGas from './details/AddressSaveOnGas'; +import FilecoinActorTag from './filecoin/FilecoinActorTag'; import TokenSelect from './tokenSelect/TokenSelect'; import useAddressCountersQuery from './utils/useAddressCountersQuery'; import type { AddressQuery } from './utils/useAddressQuery'; @@ -63,6 +66,7 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => { has_tokens: true, has_token_transfers: true, has_validated_blocks: false, + filecoin: undefined, }), [ addressHash ]); // error handling (except 404 codes) @@ -91,6 +95,49 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => { rowGap={{ base: 1, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }} overflow="hidden" > + { data.filecoin?.id && ( + <> + + ID + + + { data.filecoin.id } + + + + ) } + + { data.filecoin?.actor_type && ( + <> + + Actor + + + + + + ) } + + { (data.filecoin?.actor_type === 'evm' || data.filecoin?.actor_type === 'ethaccount') && data?.filecoin?.robust && ( + <> + + Ethereum Address + + + + + + + + + ) } + { data.is_contract && data.creation_tx_hash && data.creator_address_hash && ( diff --git a/ui/address/__screenshots__/AddressDetails.pw.tsx_default_filecoin-1.png b/ui/address/__screenshots__/AddressDetails.pw.tsx_default_filecoin-1.png new file mode 100644 index 0000000000..d657ae1500 Binary files /dev/null and b/ui/address/__screenshots__/AddressDetails.pw.tsx_default_filecoin-1.png differ diff --git a/ui/address/__screenshots__/AddressDetails.pw.tsx_default_mobile-filecoin-1.png b/ui/address/__screenshots__/AddressDetails.pw.tsx_default_mobile-filecoin-1.png new file mode 100644 index 0000000000..27606137f4 Binary files /dev/null and b/ui/address/__screenshots__/AddressDetails.pw.tsx_default_mobile-filecoin-1.png differ diff --git a/ui/address/filecoin/FilecoinActorTag.tsx b/ui/address/filecoin/FilecoinActorTag.tsx new file mode 100644 index 0000000000..55db64fd8b --- /dev/null +++ b/ui/address/filecoin/FilecoinActorTag.tsx @@ -0,0 +1,39 @@ +import { Tag } from '@chakra-ui/react'; +import React from 'react'; + +import type { FilecoinActorType } from 'types/api/address'; + +const ACTOR_TYPES: Record = { + account: 'Account', + cron: 'Scheduled Tasks', + datacap: 'Data Cap Management', + eam: 'Ethereum Address Manager', + ethaccount: 'Ethereum-Compatible Account', + evm: 'Ethereum Virtual Machine', + init: 'Initialization', + market: 'Storage Market', + miner: 'Storage Provider', + multisig: 'Multi-Signature Wallet', + paych: 'Payment Channel', + placeholder: 'Placeholder Address', + power: 'Power Management', + reward: 'Incentives and Rewards', + system: 'System Operations', + verifreg: 'Verification Registry', +}; + +type Props = { + actorType: FilecoinActorType; +} + +const FilecoinActorTag = ({ actorType }: Props) => { + const text = ACTOR_TYPES[actorType]; + + if (!text) { + return null; + } + + return { text }; +}; + +export default FilecoinActorTag; diff --git a/ui/pages/Address.tsx b/ui/pages/Address.tsx index 96b8708000..b32947920e 100644 --- a/ui/pages/Address.tsx +++ b/ui/pages/Address.tsx @@ -341,7 +341,14 @@ const AddressPageContent = () => { /> ) } { { !isLoading && !addressQuery.data?.is_contract && config.features.account.isEnabled && ( ) } - + { !isLoading && addressQuery.data?.is_contract && addressQuery.data?.is_verified && config.UI.views.address.solidityscanEnabled && diff --git a/ui/shared/entities/address/AddressEntity.tsx b/ui/shared/entities/address/AddressEntity.tsx index 514100ecf1..e36eb5b0bf 100644 --- a/ui/shared/entities/address/AddressEntity.tsx +++ b/ui/shared/entities/address/AddressEntity.tsx @@ -77,7 +77,7 @@ const Icon = (props: IconProps) => { ); @@ -115,7 +115,7 @@ const Content = chakra((props: ContentProps) => { return ( ); }); @@ -126,7 +126,7 @@ const Copy = (props: CopyProps) => { return ( ); }; diff --git a/ui/verifiedContracts/VerifiedContractsListItem.tsx b/ui/verifiedContracts/VerifiedContractsListItem.tsx index fe64a1fb05..8f47008d9d 100644 --- a/ui/verifiedContracts/VerifiedContractsListItem.tsx +++ b/ui/verifiedContracts/VerifiedContractsListItem.tsx @@ -47,9 +47,9 @@ const VerifiedContractsListItem = ({ data, isLoading }: Props) => { { data.certified && } - + - + Balance { currencyUnits.ether } diff --git a/ui/verifiedContracts/VerifiedContractsTableItem.tsx b/ui/verifiedContracts/VerifiedContractsTableItem.tsx index 0282dea6ca..2771a07f55 100644 --- a/ui/verifiedContracts/VerifiedContractsTableItem.tsx +++ b/ui/verifiedContracts/VerifiedContractsTableItem.tsx @@ -46,9 +46,9 @@ const VerifiedContractsTableItem = ({ data, isLoading }: Props) => { - + - +