From d5be7ff2bd8342108ed4e8243450f247fa76ed94 Mon Sep 17 00:00:00 2001 From: Mark Nardi Date: Tue, 9 Apr 2024 13:30:11 +0200 Subject: [PATCH] feat: show verified badge and tooltip for contracts on activities (#2286) * cleanup contract field * remove smartcontract fallback * update icon for smart contracts * improve3 check if address is magic contract * PR fixes * rename --------- Co-authored-by: Tuditi <45079109+Tuditi@users.noreply.github.com> --- .../components/AddressWithNetwork.svelte | 26 +++++++++++++------ .../activity/components/AssetPills.svelte | 2 +- .../info/EvmSmartContractInformation.svelte | 6 ++--- .../types/evm/base-evm-activity.type.ts | 3 ++- .../evm/evm-contract-call-activity.type.ts | 1 - .../evm/evm-token-transfer-activity.type.ts | 1 - ...ateEvmActivityFromBlockscoutTransaction.ts | 10 ++++--- ...erateEvmActivityFromLocalEvmTransaction.ts | 15 +++++++++-- ...sferActivityFromBlockscoutTokenTransfer.ts | 24 +++++++++++++---- .../isc-magic-contract-address.constant.ts | 1 + .../smart-contract-subject.interface.ts | 1 + .../wallet/utils/getSubjectFromAddress.ts | 6 ++--- 12 files changed, 67 insertions(+), 29 deletions(-) diff --git a/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AddressWithNetwork.svelte b/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AddressWithNetwork.svelte index 1ef272691a..f1cddd9bba 100644 --- a/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AddressWithNetwork.svelte +++ b/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AddressWithNetwork.svelte @@ -4,7 +4,7 @@ import { truncateString } from '@core/utils/string' import { Subject, SubjectType } from '@core/wallet' import { NetworkAvatar } from '@ui' - import { Text } from '@bloomwalletio/ui' + import { IconName, Text, TooltipIcon } from '@bloomwalletio/ui' import { localize } from '@core/i18n' export let subject: Subject | undefined @@ -21,7 +21,7 @@ case SubjectType.Contact: return truncateString(subject.contact.name, 13, 0) case SubjectType.SmartContract: - return truncateString(subject.name, 13, 0) + return subject.name ? truncateString(subject.name, 13, 0) : truncateString(subject.address, 5, 5) case SubjectType.Account: return truncateString(subject.account.name, 13, 0) case SubjectType.Network: @@ -36,10 +36,20 @@ {#if networkId} {/if} - - {getDisplayedSubject(subject)} - +
+ {#if subject?.type === SubjectType.SmartContract} + + {/if} + + {getDisplayedSubject(subject)} + +
diff --git a/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AssetPills.svelte b/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AssetPills.svelte index 1f413094d4..851915864c 100644 --- a/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AssetPills.svelte +++ b/packages/desktop/views/dashboard/wallet/tab-section/activity/components/AssetPills.svelte @@ -58,7 +58,7 @@ standardPill = standard typePill = standard === NftStandard.Erc721 || standard === NftStandard.Irc27 ? 'nft' : 'token' } else if (activity.type === EvmActivityType.ContractCall) { - typePill = activity.verified ? 'verified' : 'unverified' + typePill = '' standardPill = convertCamelCaseToPhrase(activity.method ?? '') } else { typePill = '' diff --git a/packages/shared/src/components/activities/evm/info/EvmSmartContractInformation.svelte b/packages/shared/src/components/activities/evm/info/EvmSmartContractInformation.svelte index ea55c15974..3bc7c7a927 100644 --- a/packages/shared/src/components/activities/evm/info/EvmSmartContractInformation.svelte +++ b/packages/shared/src/components/activities/evm/info/EvmSmartContractInformation.svelte @@ -19,12 +19,12 @@ items={[ { key: localize('general.contractAddress'), - value: activity.contractAddress || undefined, - onClick: () => onExplorerClick(activity.contractAddress ?? ''), + value: activity.contract?.address || undefined, + onClick: () => onExplorerClick(activity.contract?.address ?? ''), }, { key: localize('general.verified'), - value: activity.verified ? localize('general.yes') : localize('general.no'), + value: activity.contract?.verified ? localize('general.yes') : localize('general.no'), }, { key: localize('general.methodName'), diff --git a/packages/shared/src/lib/core/activity/types/evm/base-evm-activity.type.ts b/packages/shared/src/lib/core/activity/types/evm/base-evm-activity.type.ts index 13c7d8caa9..e5f7d3ff4a 100644 --- a/packages/shared/src/lib/core/activity/types/evm/base-evm-activity.type.ts +++ b/packages/shared/src/lib/core/activity/types/evm/base-evm-activity.type.ts @@ -1,10 +1,11 @@ import { NetworkNamespace } from '@core/network/enums' import { BaseActivity } from '../base-activity.type' +import { ISmartContractSubject } from '@core/wallet' export type BaseEvmActivity = BaseActivity & { namespace: NetworkNamespace.Evm - contractAddress?: string + contract?: ISmartContractSubject estimatedGasFee?: bigint maxGasFee?: bigint transactionFee?: bigint diff --git a/packages/shared/src/lib/core/activity/types/evm/evm-contract-call-activity.type.ts b/packages/shared/src/lib/core/activity/types/evm/evm-contract-call-activity.type.ts index b4697b3d2f..6e00dfb465 100644 --- a/packages/shared/src/lib/core/activity/types/evm/evm-contract-call-activity.type.ts +++ b/packages/shared/src/lib/core/activity/types/evm/evm-contract-call-activity.type.ts @@ -3,7 +3,6 @@ import { BaseEvmActivity } from './base-evm-activity.type' export type EvmContractCallActivity = BaseEvmActivity & { type: EvmActivityType.ContractCall - verified: boolean rawData: string methodId?: string diff --git a/packages/shared/src/lib/core/activity/types/evm/evm-token-transfer-activity.type.ts b/packages/shared/src/lib/core/activity/types/evm/evm-token-transfer-activity.type.ts index 577ff7abc4..6c8f42c4c7 100644 --- a/packages/shared/src/lib/core/activity/types/evm/evm-token-transfer-activity.type.ts +++ b/packages/shared/src/lib/core/activity/types/evm/evm-token-transfer-activity.type.ts @@ -10,7 +10,6 @@ export type EvmTokenTransferActivity = BaseEvmActivity & { tokenId: string rawAmount: bigint } - verified: boolean rawData: string methodId?: string diff --git a/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromBlockscoutTransaction.ts b/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromBlockscoutTransaction.ts index 756b0e375e..cd21c39d5e 100644 --- a/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromBlockscoutTransaction.ts +++ b/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromBlockscoutTransaction.ts @@ -11,7 +11,6 @@ import { Converter, HEX_PREFIX } from '@core/utils' import { EvmContractCallActivity } from '@core/activity/types/evm/evm-contract-call-activity.type' import { SubjectType } from '@core/wallet' import { ActivityDirection } from '@core/activity/enums' -import { localize } from '@core/i18n' import { WEI_PER_GLOW } from '@core/layer-2/constants' import { getMethodForEvmTransaction } from '@core/layer-2' import { addMethodToRegistry, getMethodFromRegistry } from '@core/layer-2/stores/method-registry.store' @@ -137,16 +136,19 @@ async function generateBaseEvmActivityFromBlockscoutTransaction( baseActivity.recipient = { type: SubjectType.SmartContract, address: blockscoutTransaction.to.hash.toLowerCase(), - name: blockscoutTransaction.to.name ?? localize('general.smartContract'), + name: blockscoutTransaction.to.name ?? '', + verified: blockscoutTransaction.to.is_verified, } - baseActivity.contractAddress = blockscoutTransaction.to.hash.toLowerCase() + baseActivity.contract = structuredClone(baseActivity.recipient) } if (blockscoutTransaction.from.is_contract) { baseActivity.sender = { type: SubjectType.SmartContract, address: blockscoutTransaction.from.hash.toLowerCase(), - name: blockscoutTransaction.from.name ?? localize('general.smartContract'), + name: blockscoutTransaction.from.name ?? '', + verified: blockscoutTransaction.from.is_verified, } + baseActivity.contract = structuredClone(baseActivity.sender) } baseActivity.subject = baseActivity.direction === ActivityDirection.Outgoing ? baseActivity.recipient : baseActivity.sender diff --git a/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromLocalEvmTransaction.ts b/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromLocalEvmTransaction.ts index 59f5c5dfe5..856c50eebd 100644 --- a/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromLocalEvmTransaction.ts +++ b/packages/shared/src/lib/core/activity/utils/evm/generateEvmActivityFromLocalEvmTransaction.ts @@ -16,6 +16,7 @@ import { BASE_TOKEN_ID, TokenStandard } from '@core/token' import { LocalEvmTransaction } from '@core/transactions' import { Converter } from '@core/utils/convert' import { generateBaseEvmActivity } from './generateBaseEvmActivity' +import { SubjectType } from '@core/wallet' export async function generateEvmActivityFromLocalEvmTransaction( transaction: LocalEvmTransaction, @@ -53,7 +54,12 @@ export async function generateEvmActivityFromLocalEvmTransaction( parameters, methodId: data.substring(0, 10), rawData: data, - contractAddress: to?.toString().toLowerCase(), + contract: { + type: SubjectType.SmartContract, + address: to?.toString().toLowerCase(), + name: '', + verified: false, + }, } as EvmContractCallActivity } else { const tokenTransfer = @@ -72,7 +78,12 @@ export async function generateEvmActivityFromLocalEvmTransaction( return { ...baseActivity, type: EvmActivityType.TokenTransfer, - contractAddress: to?.toString().toLowerCase(), + contract: { + type: SubjectType.SmartContract, + address: to?.toString().toLowerCase(), + name: '', + verified: false, + }, tokenTransfer, } as EvmTokenTransferActivity } diff --git a/packages/shared/src/lib/core/activity/utils/evm/generateEvmTokenTransferActivityFromBlockscoutTokenTransfer.ts b/packages/shared/src/lib/core/activity/utils/evm/generateEvmTokenTransferActivityFromBlockscoutTokenTransfer.ts index a305f5dbd2..a949dec33d 100644 --- a/packages/shared/src/lib/core/activity/utils/evm/generateEvmTokenTransferActivityFromBlockscoutTokenTransfer.ts +++ b/packages/shared/src/lib/core/activity/utils/evm/generateEvmTokenTransferActivityFromBlockscoutTokenTransfer.ts @@ -4,7 +4,7 @@ import { BaseEvmActivity, EvmCoinTransferActivity, EvmTokenTransferActivity } fr import { IBlockscoutTransaction } from '@auxiliary/blockscout' import { ActivityAction, ActivityDirection, InclusionState } from '@core/activity/enums' import { getAddressFromAccountForNetwork } from '@core/account' -import { getSubjectFromAddress, isSubjectInternal } from '@core/wallet' +import { ISmartContractSubject, SubjectType, getSubjectFromAddress, isSubjectInternal } from '@core/wallet' import { EvmActivityType } from '@core/activity/enums/evm' import { BASE_TOKEN_ID, TokenStandard } from '@core/token' import { NftStandard } from '@core/nfts' @@ -64,6 +64,22 @@ export async function generateEvmTokenTransferActivityFromBlockscoutTokenTransfe return } + const contract: ISmartContractSubject | undefined = blockscoutTokenTransfer.to.is_contract + ? { + type: SubjectType.SmartContract, + address: blockscoutTokenTransfer.to.hash.toLowerCase(), + name: blockscoutTokenTransfer.to.name ?? '', + verified: blockscoutTokenTransfer.to.is_verified, + } + : blockscoutTokenTransfer.from.is_contract + ? { + type: SubjectType.SmartContract, + address: blockscoutTokenTransfer.from.hash.toLowerCase(), + name: blockscoutTokenTransfer.from.name ?? '', + verified: blockscoutTokenTransfer.from.is_verified, + } + : undefined + const baseActivity: BaseEvmActivity = { namespace: NetworkNamespace.Evm, @@ -84,8 +100,7 @@ export async function generateEvmTokenTransferActivityFromBlockscoutTokenTransfe subject, direction, isInternal, - - contractAddress: blockscoutTokenTransfer.token.address.toLowerCase(), + contract, transactionFee, } @@ -126,11 +141,10 @@ export async function generateEvmTokenTransferActivityFromBlockscoutTokenTransfe rawAmount, }, - verified: blockscoutTransaction?.to.is_verified ?? false, methodId: blockscoutTransaction?.decoded_input?.method_id ?? blockscoutTransaction?.method, method, parameters, rawData: blockscoutTransaction?.raw_input ?? '', - contractAddress: blockscoutTransaction?.to?.hash.toLowerCase(), + contract, } } diff --git a/packages/shared/src/lib/core/layer-2/constants/isc-magic-contract-address.constant.ts b/packages/shared/src/lib/core/layer-2/constants/isc-magic-contract-address.constant.ts index 56ff4e17dd..9c5d7d89db 100644 --- a/packages/shared/src/lib/core/layer-2/constants/isc-magic-contract-address.constant.ts +++ b/packages/shared/src/lib/core/layer-2/constants/isc-magic-contract-address.constant.ts @@ -1 +1,2 @@ export const ISC_MAGIC_CONTRACT_ADDRESS = '0x1074000000000000000000000000000000000000' +export const ISC_BASE_COIN_ADDRESS = '0x1074010000000000000000000000000000000000' diff --git a/packages/shared/src/lib/core/wallet/interfaces/smart-contract-subject.interface.ts b/packages/shared/src/lib/core/wallet/interfaces/smart-contract-subject.interface.ts index 36289888ae..2d97706e0e 100644 --- a/packages/shared/src/lib/core/wallet/interfaces/smart-contract-subject.interface.ts +++ b/packages/shared/src/lib/core/wallet/interfaces/smart-contract-subject.interface.ts @@ -4,4 +4,5 @@ export interface ISmartContractSubject { type: SubjectType.SmartContract name: string address: string + verified: boolean } diff --git a/packages/shared/src/lib/core/wallet/utils/getSubjectFromAddress.ts b/packages/shared/src/lib/core/wallet/utils/getSubjectFromAddress.ts index 3368fc036f..3b32125c86 100644 --- a/packages/shared/src/lib/core/wallet/utils/getSubjectFromAddress.ts +++ b/packages/shared/src/lib/core/wallet/utils/getSubjectFromAddress.ts @@ -4,7 +4,7 @@ import { findActiveAccountWithAddress } from '@core/profile/actions' import { SubjectType } from '../enums' import { Subject } from '../types' import { getNetworkFromAddress } from '@core/layer-2/actions' -import { ISC_MAGIC_CONTRACT_ADDRESS } from '@core/layer-2' +import { ISC_MAGIC_CONTRACT_ADDRESS, ISC_BASE_COIN_ADDRESS } from '@core/layer-2' import { localize } from '@core/i18n' export function getSubjectFromAddress(address: string, networkId: NetworkId): Subject { @@ -13,8 +13,8 @@ export function getSubjectFromAddress(address: string, networkId: NetworkId): Su return { type: SubjectType.Account, account, address } } - if (address === ISC_MAGIC_CONTRACT_ADDRESS) { - return { type: SubjectType.SmartContract, name: localize('general.magicContract'), address } + if (address === ISC_MAGIC_CONTRACT_ADDRESS || address === ISC_BASE_COIN_ADDRESS) { + return { type: SubjectType.SmartContract, name: localize('general.magicContract'), address, verified: true } } const network = getNetworkFromAddress(address)