Commit a01299b6 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Display and handle `status` field in smart contract view (#2807)

* Display and handle `status` field in smart contract view

Fixes #2658

* change text of the alerts
parent 5feb5619
<svg viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.052 4.708c.415.037.82.204 1.141.493l.132.132c.293.323.47.746.47 1.206v3.43a1.785 1.785 0 0 1-.128.654l-.096.201a1.875 1.875 0 0 1-.58.635l-.003.002L16.796 15l5.192 3.54.014.01.145.11.013.012c.163.14.304.31.411.504l.096.201c.083.206.127.428.129.654v3.43l-.01.195a1.8 1.8 0 0 1-.46 1.012l-.133.132c-.32.29-.726.455-1.141.492l-.179.008H8.923c-.417 0-.833-.13-1.177-.384l-.142-.116a1.821 1.821 0 0 1-.567-.978l-.026-.166-.002-.016L7 23.478v-3.483l.001-.021.014-.188.002-.018.03-.166c.038-.162.098-.319.179-.464l.01-.016.098-.155.01-.015.101-.128c.104-.12.223-.225.352-.314l.016-.012L12.986 15l-5.174-3.498-.015-.012a1.889 1.889 0 0 1-.453-.442l-.118-.186a1.799 1.799 0 0 1-.21-.63L7 10.008V6.539c0-.526.233-1.004.604-1.338l.142-.116c.343-.254.76-.385 1.177-.385h11.95l.179.008ZM9.139 20.182v2.98h11.52v-2.941l-4.691-3.198v1.823a1.07 1.07 0 0 1-.96 1.063l-.11.006a1.07 1.07 0 0 1-1.069-1.07v-1.832l-4.69 3.169Zm-.121.082h.002l.006-.006-.008.006Zm5.877-6.557 2.176-1.483H12.7l2.196 1.483Zm-5.756-3.89.395.268H20.21l.45-.307v-2.94H9.138v2.98Z" fill="currentColor"/>
<path d="M21.052 4.708c.415.037.82.204 1.141.493l.132.132c.293.323.47.746.47 1.206v3.43a1.785 1.785 0 0 1-.128.654l-.096.201a1.875 1.875 0 0 1-.58.635l-.003.002L16.796 15l5.192 3.54.014.01.145.11.013.012c.163.14.304.31.411.504l.096.201c.083.206.127.428.129.654v3.43l-.01.195a1.8 1.8 0 0 1-.46 1.012l-.133.132c-.32.29-.726.455-1.141.492l-.179.008H8.923c-.417 0-.833-.13-1.177-.384l-.142-.116a1.821 1.821 0 0 1-.567-.978l-.026-.166-.002-.016L7 23.478v-3.483l.001-.021.014-.188.002-.018.03-.166c.038-.162.098-.319.179-.464l.01-.016.098-.155.01-.015.101-.128c.104-.12.223-.225.352-.314l.016-.012L12.986 15l-5.174-3.498-.015-.012a1.889 1.889 0 0 1-.453-.442l-.118-.186a1.799 1.799 0 0 1-.21-.63L7 10.008V6.539c0-.526.233-1.004.604-1.338l.142-.116c.343-.254.76-.385 1.177-.385h11.95l.179.008ZM9.139 20.182v2.98h11.52v-2.941l-4.691-3.198v1.823a1.07 1.07 0 0 1-.96 1.063l-.11.006a1.07 1.07 0 0 1-1.069-1.07v-1.832l-4.69 3.169Zm-.121.082h.002l.006-.006-.008.006Zm5.877-6.557 2.176-1.483H12.7l2.196 1.483Zm-5.756-3.89.395.268H20.21l.45-.307v-2.94H9.138v2.98Z" fill="currentColor"/>
<path d="M21.052 4.708c.415.037.82.204 1.141.493l.132.132c.293.323.47.746.47 1.206v3.43a1.785 1.785 0 0 1-.128.654l-.096.201a1.875 1.875 0 0 1-.58.635l-.003.002L16.796 15l5.192 3.54.014.01.145.11.013.012c.163.14.304.31.411.504l.096.201c.083.206.127.428.129.654v3.43l-.01.195a1.8 1.8 0 0 1-.46 1.012l-.133.132c-.32.29-.726.455-1.141.492l-.179.008H8.923c-.417 0-.833-.13-1.177-.384l-.142-.116a1.821 1.821 0 0 1-.567-.978l-.026-.166-.002-.016L7 23.478v-3.483l.001-.021.014-.188.002-.018.03-.166c.038-.162.098-.319.179-.464l.01-.016.098-.155.01-.015.101-.128c.104-.12.223-.225.352-.314l.016-.012L12.986 15l-5.174-3.498-.015-.012a1.889 1.889 0 0 1-.453-.442l-.118-.186a1.799 1.799 0 0 1-.21-.63L7 10.008V6.539a1.8 1.8 0 0 1 .604-1.338l.142-.116c.343-.254.76-.385 1.177-.385h11.95l.179.008ZM9.139 20.182v2.98h11.52v-2.941l-4.691-3.198v1.823a1.07 1.07 0 0 1-.96 1.063l-.11.006a1.07 1.07 0 0 1-1.069-1.07v-1.832l-4.69 3.169Zm-.121.082h.002l.006-.006-.008.006Zm5.877-6.557 2.176-1.483H12.7l2.196 1.483Zm-5.756-3.89.395.268H20.21l.45-.307v-2.94H9.138v2.98Z" fill="currentColor"/>
<path d="M21.052 4.708c.415.037.82.204 1.141.493l.132.132c.293.323.47.746.47 1.206v3.43a1.785 1.785 0 0 1-.128.654l-.096.201a1.875 1.875 0 0 1-.58.635l-.003.002L16.796 15l5.192 3.54.014.01.145.11.013.012c.163.14.304.31.411.504l.096.201c.083.206.127.428.129.654v3.43l-.01.195a1.8 1.8 0 0 1-.46 1.012l-.133.132c-.32.29-.726.455-1.141.492l-.179.008H8.923c-.417 0-.833-.13-1.177-.384l-.142-.116a1.821 1.821 0 0 1-.567-.978l-.026-.166-.002-.016L7 23.478v-3.483l.001-.021.014-.188.002-.018.03-.166c.038-.162.098-.319.179-.464l.01-.016.098-.155.01-.015.101-.128c.104-.12.223-.225.352-.314l.016-.012L12.986 15l-5.174-3.498-.015-.012a1.889 1.889 0 0 1-.453-.442l-.118-.186a1.799 1.799 0 0 1-.21-.63L7 10.008V6.539a1.8 1.8 0 0 1 .604-1.338l.142-.116c.343-.254.76-.385 1.177-.385h11.95l.179.008ZM9.139 20.182v2.98h11.52v-2.941l-4.691-3.198v1.823a1.07 1.07 0 0 1-.96 1.063l-.11.006a1.07 1.07 0 0 1-1.069-1.07v-1.832l-4.69 3.169Zm-.121.082h.002l.006-.006-.008.006Zm5.877-6.557 2.176-1.483H12.7l2.196 1.483Zm-5.756-3.89.395.268H20.21l.45-.307v-2.94H9.138v2.98Z" fill="currentColor"/>
</svg>
......@@ -81,6 +81,7 @@ export const token: Address = {
coin_balance: '1',
creation_transaction_hash: '0xc38cf7377bf72d6436f63c37b01b24d032101f20ec1849286dc703c712f10c98',
creator_address_hash: '0x34A9c688512ebdB575e82C50c9803F6ba2916E72',
creation_status: 'success',
exchange_rate: '0.04311',
has_logs: false,
has_token_transfers: true,
......@@ -94,6 +95,7 @@ export const eoa: Address = {
coin_balance: '2782650189688719421432220500',
creation_transaction_hash: '0xf2aff6501b632604c39978b47d309813d8a1bcca721864bbe86abf59704f195e',
creator_address_hash: '0x803ad3F50b9e1fF68615e8B053A186e1be288943',
creation_status: null,
exchange_rate: '0.04311',
has_logs: true,
has_token_transfers: false,
......@@ -117,6 +119,7 @@ export const contract: Address = {
coin_balance: '27826501896887194214322205',
creation_transaction_hash: '0xf2aff6501b632604c39978b47d309813d8a1bcca721864bbe86abf59704f195e',
creator_address_hash: '0x803ad3F50b9e1fF68615e8B053A186e1be288943',
creation_status: 'success',
exchange_rate: '0.04311',
has_logs: true,
has_token_transfers: false,
......@@ -142,6 +145,7 @@ export const validator: Address = {
coin_balance: '22910462800601256910890',
creation_transaction_hash: null,
creator_address_hash: null,
creation_status: null,
exchange_rate: '0.00432018',
has_logs: false,
has_token_transfers: false,
......
......@@ -7,6 +7,7 @@ export const verified: SmartContract = {
compiler_version: 'v0.5.16+commit.9c3226ce',
constructor_args: 'constructor_args',
creation_bytecode: 'creation_bytecode',
creation_status: 'success',
deployed_bytecode: 'deployed_bytecode',
compiler_settings: {
evmVersion: 'london',
......@@ -33,7 +34,6 @@ export const verified: SmartContract = {
],
language: 'solidity',
license_type: 'gnu_gpl_v3',
is_self_destructed: false,
is_verified_via_eth_bytecode_db: null,
is_changed_bytecode: null,
is_verified_via_sourcify: null,
......@@ -88,7 +88,7 @@ export const withProxyAddress: SmartContract = {
export const selfDestructed: SmartContract = {
...verified,
is_self_destructed: true,
creation_status: 'selfdestructed',
};
export const withChangedByteCode: SmartContract = {
......@@ -122,7 +122,7 @@ export const nonVerified: SmartContract = {
is_blueprint: false,
creation_bytecode: 'creation_bytecode',
deployed_bytecode: 'deployed_bytecode',
is_self_destructed: false,
creation_status: 'success',
abi: null,
compiler_version: null,
evm_version: null,
......
......@@ -21,6 +21,7 @@ export const ADDRESS_INFO: Address = {
coin_balance: '810941268802273085757',
creation_transaction_hash: null,
creator_address_hash: ADDRESS_HASH,
creation_status: 'success',
exchange_rate: null,
has_logs: true,
has_token_transfers: false,
......
......@@ -10,7 +10,7 @@ import { STATS_COUNTER } from './stats';
export const CONTRACT_CODE_UNVERIFIED = {
creation_bytecode: '0x60806040526e',
deployed_bytecode: '0x608060405233',
is_self_destructed: false,
creation_status: 'success',
} as SmartContract;
export const CONTRACT_CODE_VERIFIED = {
......
......@@ -2,7 +2,7 @@ import type { Transaction } from 'types/api/transaction';
import type { UserTags, AddressImplementation, AddressParam, AddressFilecoinParams } from './addressParams';
import type { Block } from './block';
import type { SmartContractProxyType } from './contract';
import type { SmartContractCreationStatus, SmartContractProxyType } from './contract';
import type { CeloEpochRewardsType } from './epochs';
import type { InternalTransaction } from './internalTransaction';
import type { MudWorldSchema, MudWorldTable } from './mudWorlds';
......@@ -15,6 +15,7 @@ export interface Address extends UserTags {
creator_address_hash: string | null;
creator_filecoin_robust_address?: string | null;
creation_transaction_hash: string | null;
creation_status: SmartContractCreationStatus | null;
exchange_rate: string | null;
ens_domain_name: string | null;
filecoin?: AddressFilecoinParams;
......
......@@ -3,6 +3,8 @@ import type { Abi, AbiType } from 'abitype';
export type SmartContractMethodArgType = AbiType;
export type SmartContractMethodStateMutability = 'view' | 'nonpayable' | 'payable';
export type SmartContractCreationStatus = 'success' | 'failed' | 'selfdestructed';
export type SmartContractLicenseType =
'none' |
'unlicense' |
......@@ -39,7 +41,7 @@ export type SmartContractProxyType =
export interface SmartContract {
deployed_bytecode: string | null;
creation_bytecode: string | null;
is_self_destructed: boolean;
creation_status: SmartContractCreationStatus | null;
abi: Abi | null;
compiler_version: string | null;
evm_version: string | null;
......
......@@ -17,6 +17,7 @@ import DetailedInfoSponsoredItem from 'ui/shared/DetailedInfo/DetailedInfoSponso
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 ContractCreationStatus from 'ui/shared/statusTag/ContractCreationStatus';
import AddressAlternativeFormat from './details/AddressAlternativeFormat';
import AddressBalance from './details/AddressBalance';
......@@ -148,6 +149,7 @@ const AddressDetails = ({ addressQuery, countersQuery, isLoading }: Props) => {
/>
<Text whiteSpace="pre"> at txn </Text>
<TxEntity hash={ data.creation_transaction_hash } truncation="constant" noIcon noCopy={ false }/>
{ data.creation_status && <ContractCreationStatus status={ data.creation_status } ml={{ base: 0, lg: 2 }}/> }
</DetailedInfo.ItemValue>
</>
) }
......
import { Flex } from '@chakra-ui/react';
import React from 'react';
import type { Address } from 'types/api/address';
import type { SmartContract } from 'types/api/contract';
import { Alert } from 'toolkit/chakra/alert';
import RawDataSnippet from 'ui/shared/RawDataSnippet';
import ContractDetailsVerificationButton from './ContractDetailsVerificationButton';
interface Props {
data: SmartContract;
isLoading: boolean;
addressData: Address;
}
const ContractDetailsByteCode = ({ data, isLoading, addressData }: Props) => {
const canBeVerified = ![ 'selfdestructed', 'failed' ].includes(data.creation_status || '') && !data?.is_verified && addressData.proxy_type !== 'eip7702';
const verificationButton = (
<ContractDetailsVerificationButton
isLoading={ isLoading }
addressHash={ addressData.hash }
isPartiallyVerified={ Boolean(data?.is_partially_verified) }
/>
);
const creationStatusText = (() => {
switch (data.creation_status) {
case 'selfdestructed':
return 'This contract self-destructed after deployment and there is no runtime bytecode. Below is the raw creation bytecode.';
case 'failed':
return 'Contract creation failed and there is no runtime bytecode. Below is the raw creation bytecode.';
default:
return null;
}
})();
return (
<Flex flexDir="column" rowGap={ 6 }>
{ data?.creation_bytecode && (
<RawDataSnippet
data={ data.creation_bytecode }
title="Contract creation code"
rightSlot={ canBeVerified ? verificationButton : null }
beforeSlot={ creationStatusText ? (
<Alert status="info" whiteSpace="pre-wrap" showIcon mb={ 3 }>
{ creationStatusText }
</Alert>
) : null }
textareaMaxHeight="300px"
isLoading={ isLoading }
/>
) }
{ data?.deployed_bytecode && (
<RawDataSnippet
data={ data.deployed_bytecode }
title="Deployed bytecode"
rightSlot={ !data?.creation_bytecode && canBeVerified ? verificationButton : null }
textareaMaxHeight="300px"
isLoading={ isLoading }
/>
) }
</Flex>
);
};
export default React.memo(ContractDetailsByteCode);
......@@ -4,12 +4,10 @@ import React from 'react';
import type { Address } from 'types/api/address';
import type { SmartContract } from 'types/api/contract';
import { Alert } from 'toolkit/chakra/alert';
import CodeViewSnippet from 'ui/shared/CodeViewSnippet';
import RawDataSnippet from 'ui/shared/RawDataSnippet';
import ContractDetailsByteCode from './ContractDetailsByteCode';
import ContractDetailsConstructorArgs from './ContractDetailsConstructorArgs';
import ContractDetailsVerificationButton from './ContractDetailsVerificationButton';
import ContractSourceCode from './ContractSourceCode';
import type { CONTRACT_DETAILS_TAB_IDS } from './utils';
......@@ -28,16 +26,7 @@ interface Props {
export default function useContractDetailsTabs({ data, isLoading, addressData, sourceAddress }: Props): Array<Tab> {
const canBeVerified = !data?.is_self_destructed && !data?.is_verified && addressData?.proxy_type !== 'eip7702';
return React.useMemo(() => {
const verificationButton = (
<ContractDetailsVerificationButton
isLoading={ isLoading }
addressHash={ addressData.hash }
isPartiallyVerified={ Boolean(data?.is_partially_verified) }
/>
);
return [
(data?.constructor_args || data?.source_code) ? {
......@@ -87,36 +76,9 @@ export default function useContractDetailsTabs({ data, isLoading, addressData, s
(data?.creation_bytecode || data?.deployed_bytecode) ? {
id: 'contract_bytecode' as const,
title: 'ByteCode',
component: (
<Flex flexDir="column" rowGap={ 6 }>
{ data?.creation_bytecode && (
<RawDataSnippet
data={ data.creation_bytecode }
title="Contract creation code"
rightSlot={ canBeVerified ? verificationButton : null }
beforeSlot={ data.is_self_destructed ? (
<Alert status="info" whiteSpace="pre-wrap" mb={ 3 }>
Contracts that self destruct in their constructors have no contract code published and cannot be verified.
Displaying the init data provided of the creating transaction.
</Alert>
) : null }
textareaMaxHeight="300px"
isLoading={ isLoading }
/>
) }
{ data?.deployed_bytecode && (
<RawDataSnippet
data={ data.deployed_bytecode }
title="Deployed ByteCode"
rightSlot={ !data?.creation_bytecode && canBeVerified ? verificationButton : null }
textareaMaxHeight="300px"
isLoading={ isLoading }
/>
) }
</Flex>
),
title: 'Bytecode',
component: <ContractDetailsByteCode data={ data } isLoading={ isLoading } addressData={ addressData }/>,
} : undefined,
].filter(Boolean);
}, [ isLoading, addressData, data, sourceAddress, canBeVerified ]);
}, [ isLoading, addressData, data, sourceAddress ]);
}
......@@ -75,6 +75,7 @@ export default function useAddressQuery({ hash, isEnabled = true }: Params): Add
coin_balance: balance.toString(),
creator_address_hash: null,
creation_transaction_hash: null,
creation_status: null,
exchange_rate: null,
ens_domain_name: null,
has_logs: false,
......
import React from 'react';
import type { SmartContractCreationStatus } from 'types/api/contract';
import type { BadgeProps } from 'toolkit/chakra/badge';
import { Badge } from 'toolkit/chakra/badge';
import { Tooltip } from 'toolkit/chakra/tooltip';
import StatusTag from './StatusTag';
interface Props extends BadgeProps {
status: SmartContractCreationStatus;
}
const ContractCreationStatus = ({ status, ...rest }: Props) => {
switch (status) {
case 'success':
return (
<Tooltip content="The contract was successfully created">
<StatusTag type="ok" text="Success" { ...rest }/>
</Tooltip>
);
case 'failed':
return (
<Tooltip content="The creation transaction failed">
<StatusTag type="error" text="Failed" { ...rest }/>
</Tooltip>
);
case 'selfdestructed':
return (
<Tooltip content="The contract was created at some point but has since self-destructed">
<Badge colorPalette="gray" { ...rest }>Self-destructed</Badge>
</Tooltip>
);
default:
return null;
}
};
export default React.memo(ContractCreationStatus);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment