From 476bceb6cf1275b9b37412945df3512e07ac0316 Mon Sep 17 00:00:00 2001 From: Mark Nardi Date: Wed, 30 Aug 2023 11:15:04 +0200 Subject: [PATCH] feat: create activity from evm transaction (#467) * generate sent evm transactions * add transaction after send * fix types * get correct subject * gas fee in activity popup Co-authored-by: MarkNerdi996 --------- Co-authored-by: Matthew Maxwell <44885822+maxwellmattryan@users.noreply.github.com> Co-authored-by: Nicole O'Brien Co-authored-by: MarkNerdi996 --- .../popups/ActivityDetailsPopup.svelte | 108 +++++++++--------- .../molecules/ActivityInformation.svelte | 20 ++-- .../GenericActivityInformation.svelte | 43 +++---- .../pills/ActivityStatusPills.svelte | 8 +- .../generateAndStoreActivitiesForAccount.ts | 9 +- .../src/lib/core/activity/actions/index.ts | 1 - .../core/activity/types/base-activity.type.ts | 1 + .../generateActivitiesFromBalanceChanges.ts | 2 +- .../utils/generateActivitiesFromChains.ts | 23 ++++ ...rateActivitiesFromProcessedTransactions.ts | 2 +- .../generateActivityFromEvmTransaction.ts | 36 ++++++ .../src/lib/core/activity/utils/index.ts | 3 + .../actions/send/sendTransactionFromEvm.ts | 19 ++- packages/shared/src/locales/en.json | 1 + 14 files changed, 169 insertions(+), 107 deletions(-) rename packages/shared/src/lib/core/activity/{actions => utils}/generateActivitiesFromBalanceChanges.ts (92%) create mode 100644 packages/shared/src/lib/core/activity/utils/generateActivitiesFromChains.ts rename packages/shared/src/lib/core/activity/{actions => utils}/generateActivitiesFromProcessedTransactions.ts (93%) create mode 100644 packages/shared/src/lib/core/activity/utils/generateActivityFromEvmTransaction.ts diff --git a/packages/desktop/components/popups/ActivityDetailsPopup.svelte b/packages/desktop/components/popups/ActivityDetailsPopup.svelte index a0eb5c879c..f9b416bb6f 100644 --- a/packages/desktop/components/popups/ActivityDetailsPopup.svelte +++ b/packages/desktop/components/popups/ActivityDetailsPopup.svelte @@ -65,18 +65,18 @@ $collectiblesRouter.goTo(CollectiblesRoute.Details) } - function onExplorerClick(): void { - openUrlInBrowser(`${explorerUrl}/${ExplorerEndpoint.Transaction}/${activity?.transactionId}`) + function onExplorerClick(_activity: Activity): void { + openUrlInBrowser(`${explorerUrl}/${ExplorerEndpoint.Transaction}/${_activity.transactionId}`) } - function onTransactionIdClick(): void { - setClipboard(activity?.transactionId) + function onTransactionIdClick(_activity: Activity): void { + setClipboard(_activity.transactionId) } - async function onClaimClick(): Promise { + async function onClaimClick(_activity: Activity): Promise { await checkActiveProfileAuth( async () => { - await claimActivity(activity) + await claimActivity(_activity) openPopup({ id: PopupId.ActivityDetails, props: { activityId }, @@ -118,52 +118,54 @@ }) - -
- - {title} - - {#if explorerUrl && activity?.transactionId} - - {:else if activity?.transactionId} - - {/if} -
- - +{#if activity} + +
+ + {title} + + {#if explorerUrl && activity.transactionId} + + {:else if activity.transactionId} + + {/if} +
+ + - + - - - {#if !isTimelocked && isActivityIncomingAndUnclaimed} - - - - - {/if} -
+ +
+ {#if !isTimelocked && isActivityIncomingAndUnclaimed} + + + + + {/if} +
+{/if} diff --git a/packages/shared/src/components/molecules/ActivityInformation.svelte b/packages/shared/src/components/molecules/ActivityInformation.svelte index 07c76eeb8c..4c121eb0a2 100644 --- a/packages/shared/src/components/molecules/ActivityInformation.svelte +++ b/packages/shared/src/components/molecules/ActivityInformation.svelte @@ -22,17 +22,17 @@ let hasMetadata = false $: { const storedNft = - activity?.type === ActivityType.Nft - ? getNftByIdFromAllAccountNfts($selectedAccountIndex, activity?.nftId) + activity.type === ActivityType.Nft + ? getNftByIdFromAllAccountNfts($selectedAccountIndex, activity.nftId) : undefined hasMetadata = !!storedNft?.metadata } let tabs: Tab[] = [] $: { - switch (activity?.type) { + switch (activity.type) { case ActivityType.Basic: - tabs = [Tab.Transaction, ...(activity?.parsedLayer2Metadata ? [Tab.SmartContract] : [])] + tabs = [Tab.Transaction, ...(activity.parsedLayer2Metadata ? [Tab.SmartContract] : [])] break case ActivityType.Governance: tabs = [Tab.Transaction] @@ -48,7 +48,7 @@ Tab.Transaction, Tab.Nft, ...(hasMetadata ? [Tab.NftMetadata] : []), - ...(activity?.parsedLayer2Metadata ? [Tab.SmartContract] : []), + ...(activity.parsedLayer2Metadata ? [Tab.SmartContract] : []), ] break case ActivityType.Foundry: @@ -63,22 +63,22 @@ {/if} {#if activeTab === Tab.Transaction} - {#if activity?.type === ActivityType.Governance} + {#if activity.type === ActivityType.Governance} - {:else if activity?.type === ActivityType.Consolidation} + {:else if activity.type === ActivityType.Consolidation} {:else} {/if} - {:else if activeTab === Tab.Alias && activity?.type === ActivityType.Alias} + {:else if activeTab === Tab.Alias && activity.type === ActivityType.Alias} - {:else if activeTab === Tab.Nft && activity?.type === ActivityType.Nft} + {:else if activeTab === Tab.Nft && activity.type === ActivityType.Nft} {:else if activeTab === Tab.Foundry} {:else if activeTab === Tab.Token} - {:else if activeTab === Tab.NftMetadata && activity?.type === ActivityType.Nft} + {:else if activeTab === Tab.NftMetadata && activity.type === ActivityType.Nft} {:else if activeTab === Tab.SmartContract} diff --git a/packages/shared/src/components/molecules/activity-info/GenericActivityInformation.svelte b/packages/shared/src/components/molecules/activity-info/GenericActivityInformation.svelte index 3a9ebb2d9f..5e71d52a87 100644 --- a/packages/shared/src/components/molecules/activity-info/GenericActivityInformation.svelte +++ b/packages/shared/src/components/molecules/activity-info/GenericActivityInformation.svelte @@ -7,18 +7,19 @@ export let activity: Activity - $: expirationTime = getFormattedTimeStamp(activity?.asyncData?.expirationDate) - $: claimedTime = getFormattedTimeStamp(activity?.asyncData?.claimedDate) - $: hasStorageDeposit = - activity?.storageDeposit || (activity?.storageDeposit === 0 && activity?.giftedStorageDeposit === 0) - $: gasLimit = activity?.parsedLayer2Metadata?.gasLimit + $: expirationTime = activity?.asyncData?.expirationDate + ? getFormattedTimeStamp(activity?.asyncData?.expirationDate) + : undefined + $: claimedTime = activity?.asyncData?.claimedDate + ? getFormattedTimeStamp(activity?.asyncData?.claimedDate) + : undefined + $: hasStorageDeposit = activity?.storageDeposit + $: gasFee = activity?.parsedLayer2Metadata?.gasLimit || activity?.gasUsed - $: formattedTransactionTime = getFormattedTimeStamp(activity?.time) - $: formattedTimelockDate = getFormattedTimeStamp(activity?.asyncData?.timelockDate) - $: formattedStorageDeposit = formatTokenAmountPrecise(activity?.storageDeposit ?? 0, getBaseToken()) - $: formattedGiftedStorageDeposit = formatTokenAmountPrecise(activity?.giftedStorageDeposit ?? 0, getBaseToken()) - $: formattedSurplus = formatTokenAmountPrecise(activity?.surplus ?? 0, getBaseToken()) - $: formattedGasLimit = formatTokenAmountPrecise(Number(gasLimit ?? 0), getBaseToken()) + $: formattedTransactionTime = getFormattedTimeStamp(activity.time) + $: formattedTimelockDate = activity.asyncData ? getFormattedTimeStamp(activity.asyncData?.timelockDate) : undefined + $: formattedStorageDeposit = formatTokenAmountPrecise(activity.storageDeposit ?? 0, getBaseToken()) + $: formattedGasFee = formatTokenAmountPrecise(Number(gasFee ?? 0), getBaseToken()) let items: IItem[] = [] @@ -60,24 +61,10 @@ tooltip: localize(`tooltips.transactionDetails.${_activity?.direction}.storageDeposit`), }) } - if (_activity?.surplus) { + if (gasFee) { items.push({ - key: localize('general.surplus'), - value: formattedSurplus, - }) - } - if (_activity?.giftedStorageDeposit) { - items.push({ - key: localize('general.giftedStorageDeposit'), - value: formattedGiftedStorageDeposit, - tooltip: localize(`tooltips.transactionDetails.${_activity?.direction}.giftedStorageDeposit`), - }) - } - if (gasLimit) { - items.push({ - key: localize('general.gasLimit'), - value: formattedGasLimit, - tooltip: localize(`tooltips.transactionDetails.${_activity?.direction}.gasLimit`), + key: localize('general.gasFee'), + value: formattedGasFee, }) } if (expirationTime) { diff --git a/packages/shared/src/components/pills/ActivityStatusPills.svelte b/packages/shared/src/components/pills/ActivityStatusPills.svelte index 7bd80285e5..a82edaec53 100644 --- a/packages/shared/src/components/pills/ActivityStatusPills.svelte +++ b/packages/shared/src/components/pills/ActivityStatusPills.svelte @@ -11,20 +11,20 @@ $: isTimelocked = timelockDate && timelockDate > $time $: hasPills = - (activity.asyncData?.asyncStatus && activity?.asyncData?.asyncStatus !== ActivityAsyncStatus.Timelocked) || + (activity.asyncData?.asyncStatus && activity.asyncData?.asyncStatus !== ActivityAsyncStatus.Timelocked) || isTimelocked || - activity?.parsedLayer2Metadata + activity.parsedLayer2Metadata {#if hasPills} - {#if activity.asyncData?.asyncStatus && activity?.asyncData?.asyncStatus !== ActivityAsyncStatus.Timelocked} + {#if activity.asyncData?.asyncStatus && activity.asyncData?.asyncStatus !== ActivityAsyncStatus.Timelocked} {/if} {#if isTimelocked} {/if} - {#if activity?.parsedLayer2Metadata} + {#if activity.parsedLayer2Metadata} {localize('pills.smartContract')} diff --git a/packages/shared/src/lib/core/activity/actions/generateAndStoreActivitiesForAccount.ts b/packages/shared/src/lib/core/activity/actions/generateAndStoreActivitiesForAccount.ts index 97069577bf..0908dae4cb 100644 --- a/packages/shared/src/lib/core/activity/actions/generateAndStoreActivitiesForAccount.ts +++ b/packages/shared/src/lib/core/activity/actions/generateAndStoreActivitiesForAccount.ts @@ -6,10 +6,11 @@ import { preprocessTransactionsForAccount } from './preprocessTransactionsForAcc import { preprocessOutputsForAccount } from './preprocessOutputsForAccount' import { linkTransactionsWithClaimingTransactions } from './linkTransactionsWithClaimingTransactions' import { hideActivitiesForFoundries } from './hideActivitiesForFoundries' -import { generateActivitiesFromProcessedTransactions } from './generateActivitiesFromProcessedTransactions' +import { generateActivitiesFromProcessedTransactions } from '../utils/generateActivitiesFromProcessedTransactions' import { loadAssetsForAllActivities } from './loadAssetsForAllAccounts' -import { generateActivitiesFromBalanceChanges, setOutgoingAsyncActivitiesToClaimed } from '@core/activity/actions' +import { generateActivitiesFromBalanceChanges, generateActivitiesFromChains } from '../utils' import { NetworkId } from '@core/network' +import { setOutgoingAsyncActivitiesToClaimed } from './setOutgoingAsyncActivitiesToClaimed' export async function generateAndStoreActivitiesForAccount( account: IAccountState, @@ -27,9 +28,11 @@ export async function generateAndStoreActivitiesForAccount( // Step 3: generate activities from processed transactions const activities = generateActivitiesFromProcessedTransactions(linkedProcessedTransactions, account, networkId) const balanceChangeActivities = generateActivitiesFromBalanceChanges(account) - activities.push(...balanceChangeActivities) + const chainActivities = await generateActivitiesFromChains(account) + activities.push(...chainActivities) + // Step 4: set account activities with generated activities setAccountActivitiesInAllAccountActivities(account.index, activities) diff --git a/packages/shared/src/lib/core/activity/actions/index.ts b/packages/shared/src/lib/core/activity/actions/index.ts index c38a675acf..746dadb3e5 100644 --- a/packages/shared/src/lib/core/activity/actions/index.ts +++ b/packages/shared/src/lib/core/activity/actions/index.ts @@ -1,5 +1,4 @@ export * from './calculateAndAddPersistedBalanceChange' -export * from './generateActivitiesFromBalanceChanges' export * from './generateAndStoreActivitiesForAccount' export * from './generateAndStoreActivitiesForAllAccounts' export * from './hideActivitiesForFoundries' diff --git a/packages/shared/src/lib/core/activity/types/base-activity.type.ts b/packages/shared/src/lib/core/activity/types/base-activity.type.ts index bdc12a3e81..3cd126fa98 100644 --- a/packages/shared/src/lib/core/activity/types/base-activity.type.ts +++ b/packages/shared/src/lib/core/activity/types/base-activity.type.ts @@ -16,6 +16,7 @@ export type BaseActivity = { action: ActivityAction isInternal: boolean storageDeposit: number + gasUsed?: number rawBaseCoinAmount?: number subject: Subject | undefined metadata?: string diff --git a/packages/shared/src/lib/core/activity/actions/generateActivitiesFromBalanceChanges.ts b/packages/shared/src/lib/core/activity/utils/generateActivitiesFromBalanceChanges.ts similarity index 92% rename from packages/shared/src/lib/core/activity/actions/generateActivitiesFromBalanceChanges.ts rename to packages/shared/src/lib/core/activity/utils/generateActivitiesFromBalanceChanges.ts index c985c82adb..2ea7d06e0b 100644 --- a/packages/shared/src/lib/core/activity/actions/generateActivitiesFromBalanceChanges.ts +++ b/packages/shared/src/lib/core/activity/utils/generateActivitiesFromBalanceChanges.ts @@ -3,7 +3,7 @@ import { Activity } from '../types' import { getBalanceChanges } from '../stores' import { get } from 'svelte/store' import { network } from '@core/network' -import { generateBalanceChangeActivity } from '../utils' +import { generateBalanceChangeActivity } from './generateBalanceChangeActivity' export function generateActivitiesFromBalanceChanges(account: IAccountState): Activity[] { const activities: Activity[] = [] diff --git a/packages/shared/src/lib/core/activity/utils/generateActivitiesFromChains.ts b/packages/shared/src/lib/core/activity/utils/generateActivitiesFromChains.ts new file mode 100644 index 0000000000..128dd28bf9 --- /dev/null +++ b/packages/shared/src/lib/core/activity/utils/generateActivitiesFromChains.ts @@ -0,0 +1,23 @@ +import { IAccountState } from '@core/account' +import { Activity } from '../types' +import { getPersistedEvmTransactions } from '../stores' +import { generateActivityFromEvmTransaction } from './generateActivityFromEvmTransaction' +import { get } from 'svelte/store' +import { network } from '@core/network' + +export async function generateActivitiesFromChains(account: IAccountState): Promise { + const activities: Activity[] = [] + + const chains = get(network)?.getChains() ?? [] + for (const chain of chains) { + const networkId = chain.getConfiguration().id + + const transactions = getPersistedEvmTransactions(account.index, networkId) + for (const transaction of transactions) { + const activity = await generateActivityFromEvmTransaction(transaction, networkId, chain.getProvider()) + activities.push(activity) + } + } + + return activities +} diff --git a/packages/shared/src/lib/core/activity/actions/generateActivitiesFromProcessedTransactions.ts b/packages/shared/src/lib/core/activity/utils/generateActivitiesFromProcessedTransactions.ts similarity index 93% rename from packages/shared/src/lib/core/activity/actions/generateActivitiesFromProcessedTransactions.ts rename to packages/shared/src/lib/core/activity/utils/generateActivitiesFromProcessedTransactions.ts index 194cb497b0..0988a949ec 100644 --- a/packages/shared/src/lib/core/activity/actions/generateActivitiesFromProcessedTransactions.ts +++ b/packages/shared/src/lib/core/activity/utils/generateActivitiesFromProcessedTransactions.ts @@ -1,6 +1,6 @@ import { IAccountState } from '@core/account' import { Activity, IProcessedTransaction } from '../types' -import { generateActivities } from '../utils' +import { generateActivities } from '.' import { NetworkId } from '@core/network/types' export function generateActivitiesFromProcessedTransactions( diff --git a/packages/shared/src/lib/core/activity/utils/generateActivityFromEvmTransaction.ts b/packages/shared/src/lib/core/activity/utils/generateActivityFromEvmTransaction.ts new file mode 100644 index 0000000000..98f3fcf367 --- /dev/null +++ b/packages/shared/src/lib/core/activity/utils/generateActivityFromEvmTransaction.ts @@ -0,0 +1,36 @@ +import { PersistedEvmTransaction, TransactionActivity } from '../types' +import { ActivityAction, ActivityDirection, ActivityType, InclusionState } from '../enums' +import { getCoinType } from '@core/profile/actions' +import { getSubjectFromAddress } from '@core/wallet' +import { WEI_PER_GLOW } from '@core/layer-2' +import Web3 from 'web3' +import { NetworkId } from '@core/network/types' + +export async function generateActivityFromEvmTransaction( + transaction: PersistedEvmTransaction, + networkId: NetworkId, + provider: Web3 +): Promise { + const direction = ActivityDirection.Outgoing // Currently only sent transactions are supported + + const subject = getSubjectFromAddress(transaction.to, networkId) + const timestamp = (await provider.eth.getBlock(transaction.blockNumber)).timestamp + return { + type: ActivityType.Basic, + id: transaction.transactionHash, + time: new Date(Number(timestamp) * 1000), + inclusionState: InclusionState.Confirmed, + containsValue: true, + isAssetHidden: false, + direction, + action: ActivityAction.Send, + isInternal: false, + storageDeposit: 0, + gasUsed: transaction.gasUsed, + subject, + rawBaseCoinAmount: Number(transaction.value) / Number(WEI_PER_GLOW), + rawAmount: Number(transaction.value) / Number(WEI_PER_GLOW), + tokenId: getCoinType(), + networkId, + } +} diff --git a/packages/shared/src/lib/core/activity/utils/index.ts b/packages/shared/src/lib/core/activity/utils/index.ts index bb13a4f855..eba4c29621 100644 --- a/packages/shared/src/lib/core/activity/utils/index.ts +++ b/packages/shared/src/lib/core/activity/utils/index.ts @@ -1,9 +1,12 @@ export * from './activityOutputContainsValue' export * from './generateActivities' export * from './generateActivitiesFromAliasOutputs' +export * from './generateActivitiesFromBalanceChanges' export * from './generateActivitiesFromBasicOutputs' +export * from './generateActivitiesFromChains' export * from './generateActivitiesFromFoundryOutputs' export * from './generateActivitiesFromNftOutputs' +export * from './generateActivitiesFromProcessedTransactions' export * from './generateBalanceChangeActivity' export * from './generateSingleAliasActivity' export * from './generateSingleBasicActivity' diff --git a/packages/shared/src/lib/core/wallet/actions/send/sendTransactionFromEvm.ts b/packages/shared/src/lib/core/wallet/actions/send/sendTransactionFromEvm.ts index d6b53945fb..37da407297 100644 --- a/packages/shared/src/lib/core/wallet/actions/send/sendTransactionFromEvm.ts +++ b/packages/shared/src/lib/core/wallet/actions/send/sendTransactionFromEvm.ts @@ -1,11 +1,13 @@ import { getSelectedAccount } from '@core/account/stores' -import { addPersistedTransaction } from '@core/activity/stores' -import { EvmTransactionData } from '@core/layer-2/types' -import { LedgerAppName } from '@core/ledger/enums' -import { IChain } from '@core/network/interfaces' +import { addActivitiesToAccountActivitiesInAllAccountActivities, addPersistedTransaction } from '@core/activity/stores' +import { EvmTransactionData } from '@core/layer-2' +import { LedgerAppName } from '@core/ledger' +import { IChain } from '@core/network' import { checkActiveProfileAuth } from '@core/profile/actions' import { signAndSendEvmTransaction } from './signAndSendEvmTransaction' +import { generateActivityFromEvmTransaction } from '@core/activity/utils/generateActivityFromEvmTransaction' +import { PersistedEvmTransaction } from '@core/activity' export async function sendTransactionFromEvm( transaction: EvmTransactionData, @@ -28,10 +30,15 @@ export async function sendTransactionFromEvm( account ) if (transactionReceipt) { - addPersistedTransaction(account.index, networkId, { + const evmTransaction: PersistedEvmTransaction = { ...transaction, ...transactionReceipt, - }) + } + addPersistedTransaction(account.index, networkId, evmTransaction) + + const activity = await generateActivityFromEvmTransaction(evmTransaction, networkId, provider) + addActivitiesToAccountActivitiesInAllAccountActivities(account.index, [activity]) + if (callback && typeof callback === 'function') { callback() } diff --git a/packages/shared/src/locales/en.json b/packages/shared/src/locales/en.json index 086fd74542..2ed1612d51 100644 --- a/packages/shared/src/locales/en.json +++ b/packages/shared/src/locales/en.json @@ -1728,6 +1728,7 @@ "transactionTime": "Transaction time", "surplus": "Surplus", "storageDeposit": "Storage deposit", + "gasFee": "Gas fee", "giftedStorageDeposit": "Gifted storage deposit", "storageDepositPerNft": "Storage deposit per NFT", "totalStorageDeposit": "Total storage deposit",