Skip to content

Display and handle status field in smart contract view #2807

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions mocks/address/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions mocks/contract/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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,
Expand Down Expand Up @@ -88,7 +88,7 @@ export const withProxyAddress: SmartContract = {

export const selfDestructed: SmartContract = {
...verified,
is_self_destructed: true,
creation_status: 'selfdestructed',
};

export const withChangedByteCode: SmartContract = {
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions stubs/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion stubs/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
3 changes: 2 additions & 1 deletion types/api/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Transaction } from 'types/api/transaction';

import type { UserTags, AddressImplementation, AddressParam, AddressFilecoinParams } from './addressParams';
import type { Block, EpochRewardsType } from './block';
import type { SmartContractProxyType } from './contract';
import type { SmartContractCreationStatus, SmartContractProxyType } from './contract';
import type { InternalTransaction } from './internalTransaction';
import type { MudWorldSchema, MudWorldTable } from './mudWorlds';
import type { NFTTokenType, TokenInfo, TokenInstance, TokenType } from './token';
Expand All @@ -14,6 +14,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;
Expand Down
4 changes: 3 additions & 1 deletion types/api/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' |
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions ui/address/AddressDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -152,6 +153,7 @@ const AddressDetails = ({ addressQuery, 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>
</>
) }
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 69 additions & 0 deletions ui/address/contract/ContractDetailsByteCode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
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);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 4 additions & 42 deletions ui/address/contract/useContractDetailsTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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) ? {
Expand Down Expand Up @@ -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 ]);
}
1 change: 1 addition & 0 deletions ui/address/utils/useAddressQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
40 changes: 40 additions & 0 deletions ui/shared/statusTag/ContractCreationStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
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);
Loading