diff --git a/configs/envs/.env.eth_sepolia b/configs/envs/.env.eth_sepolia index 7c75dd73d9..2b54a8faea 100644 --- a/configs/envs/.env.eth_sepolia +++ b/configs/envs/.env.eth_sepolia @@ -14,31 +14,38 @@ NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={ "id": "632019", "width": "728", "height NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={ "id": "632018", "width": "320", "height": "100" } NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com NEXT_PUBLIC_API_BASE_PATH=/ -NEXT_PUBLIC_API_HOST=eth-sepolia.k8s-dev.blockscout.com +NEXT_PUBLIC_API_HOST=eth-sepolia.blockscout.com NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}] NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED=true -NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'cow-swap'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'},{'text':'Get gas','icon':'gas','dappId':'smol-refuel'}] +NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'cow-swap'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'}] NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-sepolia.json NEXT_PUBLIC_FOOTER_LINKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/footer-links/sepolia.json NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xbf69c7abc4fee283b59a9633dadfdaedde5c5ee0fba3e80a08b5b8a3acbd4363 NEXT_PUBLIC_HAS_BEACON_CHAIN=true NEXT_PUBLIC_HAS_USER_OPS=true NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs'] +NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['rgba(51, 53, 67, 1)'],'text_color':['rgba(165, 252, 122, 1)']} NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true NEXT_PUBLIC_IS_TESTNET=true NEXT_PUBLIC_LOGOUT_URL=https://blockscout-goerli.us.auth0.com/v2/logout +NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE=

Participated in our recent Blockscout activities? Check your eligibility and claim your NFT Scout badges. More exciting things are coming soon!

+NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maikReal/974c47f86a3158c1a86b092ae2f044b3/raw/abcc7e02150cd85d4974503a0357162c0a2c35a9/merits-banner.html +NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://swap.blockscout.com?utm_source=blockscout&utm_medium=eth-sepolia NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json NEXT_PUBLIC_MARKETPLACE_ENABLED=true +NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_API_KEY=patbqG4V2CI998jAq.9810c58c9de973ba2650621c94559088cbdfa1a914498e385621ed035d33c0d0 +NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_BASE_ID=appGkvtmKI7fXE4Vs NEXT_PUBLIC_MARKETPLACE_SECURITY_REPORTS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-security-reports/default.json NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6uMGPKjj1DK7NL NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com NEXT_PUBLIC_METASUITES_ENABLED=true -NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'dapp_id': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}] +NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'},{'name': 'zapper', 'url_template': 'https://zapper.xyz/account/{address}', 'logo': 'https://blockscout-content.s3.amazonaws.com/zapper-icon.png'}] NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com -NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps','/account/rewards'] +NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps'] +NEXT_PUBLIC_NAVIGATION_LAYOUT=horizontal NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH @@ -55,11 +62,11 @@ NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/sepolia-testnet.png NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://sepolia.drpc.org?ref=559183','text':'Public RPC'}] +NEXT_PUBLIC_REWARDS_SERVICE_API_HOST=https://merits.blockscout.com NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-sepolia.safe.global NEXT_PUBLIC_SENTRY_ENABLE_TRACING=true -NEXT_PUBLIC_STATS_API_HOST=https://stats-sepolia.k8s-dev.blockscout.com +NEXT_PUBLIC_STATS_API_HOST=https://stats-sepolia.k8s.blockscout.com NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=noves NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com -NEXT_PUBLIC_REWARDS_SERVICE_API_HOST=https://points.k8s-dev.blockscout.com -NEXT_PUBLIC_XSTAR_SCORE_URL=https://docs.xname.app/the-solution-adaptive-proof-of-humanity-on-blockchain/xhs-scoring-algorithm?utm_source=blockscout&utm_medium=address +NEXT_PUBLIC_XSTAR_SCORE_URL=https://docs.xname.app/the-solution-adaptive-proof-of-humanity-on-blockchain/xhs-scoring-algorithm?utm_source=blockscout&utm_medium=address \ No newline at end of file diff --git a/mocks/contract/info.ts b/mocks/contract/info.ts index daedb99650..ab4ee68af8 100644 --- a/mocks/contract/info.ts +++ b/mocks/contract/info.ts @@ -24,7 +24,7 @@ export const verified: SmartContract = { verified_at: '2021-08-03T10:40:41.679421Z', decoded_constructor_args: [ [ '0xc59615da2da226613b1c78f0c6676cac497910bc', { internalType: 'address', name: '_token', type: 'address' } ], - [ '1800', { internalType: 'uint256', name: '_duration', type: 'uint256' } ], + [ [ 1800, 3600, 7200 ], { internalType: 'uint256[]', name: '_durations', type: 'uint256[]' } ], [ '900000000', { internalType: 'uint256', name: '_totalSupply', type: 'uint256' } ], ], external_libraries: [ diff --git a/types/api/contract.ts b/types/api/contract.ts index 600e38927f..eed6aa34ef 100644 --- a/types/api/contract.ts +++ b/types/api/contract.ts @@ -76,7 +76,7 @@ export interface SmartContract { } export type SmartContractDecodedConstructorArg = [ - string, + unknown, { internalType: SmartContractMethodArgType; name: string; diff --git a/ui/address/contract/ContractDetailsConstructorArgs.tsx b/ui/address/contract/ContractDetailsConstructorArgs.tsx new file mode 100644 index 0000000000..20764a5cc7 --- /dev/null +++ b/ui/address/contract/ContractDetailsConstructorArgs.tsx @@ -0,0 +1,106 @@ +import { Box } from '@chakra-ui/react'; +import React from 'react'; + +import type { SmartContract } from 'types/api/contract'; + +import AddressEntity from 'ui/shared/entities/address/AddressEntity'; +import type { Truncation } from 'ui/shared/entities/base/components'; +import RawDataSnippet from 'ui/shared/RawDataSnippet'; + +import { matchArray } from './methods/form/utils'; + +interface DecodedItemProps { + value: unknown; + type: string; + addressTruncation?: Truncation; +} + +const DecodedItemValue = ({ value, type, addressTruncation = 'dynamic' }: DecodedItemProps) => { + const arrayMatch = matchArray(type); + + if (arrayMatch && Array.isArray(value)) { + return value.map((item, index) => ( + <> + + { index < value.length - 1 && ', ' } + + )); + } + + if (type === 'address' && typeof value === 'string') { + return ( + + ); + } + + const content = (() => { + if (value === null || value === undefined || value === '') { + return '""'; + } + + if (typeof value === 'object') { + return JSON.stringify(value); + } + + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + return value; + } + + return String(value); + })(); + + return { content }; +}; + +interface Props { + data: SmartContract | undefined; + isLoading: boolean; +} + +const ContractDetailsConstructorArgs = ({ data, isLoading }: Props) => { + + const content = React.useMemo(() => { + if (!data?.decoded_constructor_args) { + return data?.constructor_args; + } + + const decoded = data.decoded_constructor_args + .map(([ value, { name, type } ], index) => { + return ( + + Arg [{ index }] { name || '' } ({ type }): + + + ); + }); + + return ( + <> + { data.constructor_args } +

+ { decoded } + + ); + }, [ data?.constructor_args, data?.decoded_constructor_args ]); + + if (!content) { + return null; + } + + return ( + + ); +}; + +export default React.memo(ContractDetailsConstructorArgs); diff --git a/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_dark-color-mode_full-view-source-code-dark-mode-1.png b/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_dark-color-mode_full-view-source-code-dark-mode-1.png index d5b3fd8417..13dfa65eec 100644 Binary files a/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_dark-color-mode_full-view-source-code-dark-mode-1.png and b/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_dark-color-mode_full-view-source-code-dark-mode-1.png differ diff --git a/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_default_full-view-source-code-dark-mode-1.png b/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_default_full-view-source-code-dark-mode-1.png index eb47124dde..fe1b669d1b 100644 Binary files a/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_default_full-view-source-code-dark-mode-1.png and b/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_default_full-view-source-code-dark-mode-1.png differ diff --git a/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_default_mobile-view-source-code-1.png b/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_default_mobile-view-source-code-1.png index 58edaeecc6..a238a1e886 100644 Binary files a/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_default_mobile-view-source-code-1.png and b/ui/address/contract/__screenshots__/ContractDetails.pw.tsx_default_mobile-view-source-code-1.png differ diff --git a/ui/address/contract/useContractDetailsTabs.tsx b/ui/address/contract/useContractDetailsTabs.tsx index 89dbf2c474..3d124f6831 100644 --- a/ui/address/contract/useContractDetailsTabs.tsx +++ b/ui/address/contract/useContractDetailsTabs.tsx @@ -1,11 +1,11 @@ -import { Alert, Box, Flex } from '@chakra-ui/react'; +import { Alert, Flex } from '@chakra-ui/react'; import React from 'react'; import type { SmartContract } from 'types/api/contract'; -import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import RawDataSnippet from 'ui/shared/RawDataSnippet'; +import ContractDetailsConstructorArgs from './ContractDetailsConstructorArgs'; import ContractDetailsVerificationButton from './ContractDetailsVerificationButton'; import ContractSourceCode from './ContractSourceCode'; import type { CONTRACT_DETAILS_TAB_IDS } from './utils'; @@ -25,38 +25,6 @@ interface Props { export default function useContractDetailsTabs({ data, isLoading, addressHash, sourceAddress }: Props): Array { - const constructorArgs = React.useMemo(() => { - if (!data?.decoded_constructor_args) { - return data?.constructor_args; - } - - const decoded = data.decoded_constructor_args - .map(([ value, { name, type } ], index) => { - const valueEl = type === 'address' ? ( - - ) : { value }; - return ( - - Arg [{ index }] { name || '' } ({ type }): - { valueEl } - - ); - }); - - return ( - <> - { data.constructor_args } -

- { decoded } - - ); - }, [ data?.decoded_constructor_args, data?.constructor_args ]); - const canBeVerified = !data?.is_self_destructed && !data?.is_verified; return React.useMemo(() => { @@ -69,19 +37,12 @@ export default function useContractDetailsTabs({ data, isLoading, addressHash, s ); return [ - (constructorArgs || data?.source_code) ? { + (data?.constructor_args || data?.source_code) ? { id: 'contract_source_code' as const, title: 'Code', component: ( - { constructorArgs && ( - - ) } + { data?.source_code && (