From e73bd56ab82bd2e8caf23f4efc4c2e613dd1acb3 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Fri, 22 Mar 2024 09:13:00 +0100 Subject: [PATCH 1/3] feat: Sync SDK types --- .../TransactionActivityTileContent.svelte | 2 +- .../utils/getNetworkIdFromNetworkName.ts | 2 +- .../utils/outputs/preprocessGroupedOutputs.ts | 35 +++++++------------ .../outputs/preprocessOutgoingTransaction.ts | 9 +++-- 4 files changed, 18 insertions(+), 30 deletions(-) diff --git a/packages/shared/components/tiles/tileContents/TransactionActivityTileContent.svelte b/packages/shared/components/tiles/tileContents/TransactionActivityTileContent.svelte index 7620eb1adbe..2f449f81011 100644 --- a/packages/shared/components/tiles/tileContents/TransactionActivityTileContent.svelte +++ b/packages/shared/components/tiles/tileContents/TransactionActivityTileContent.svelte @@ -21,7 +21,7 @@ activity.direction === ActivityDirection.SelfTransaction ? localize('general.internalTransaction') : localize(isIncoming ? 'general.fromAddress' : 'general.toAddress', { - values: { account: getSubjectLocaleFromActivity(activity) }, + values: { address: getSubjectLocaleFromActivity(activity) }, }) $: amount = getFormattedAmountFromActivity(activity) diff --git a/packages/shared/lib/core/network/utils/getNetworkIdFromNetworkName.ts b/packages/shared/lib/core/network/utils/getNetworkIdFromNetworkName.ts index e9078c25d84..73e5391c05f 100644 --- a/packages/shared/lib/core/network/utils/getNetworkIdFromNetworkName.ts +++ b/packages/shared/lib/core/network/utils/getNetworkIdFromNetworkName.ts @@ -14,7 +14,7 @@ export function getNetworkIdFromNetworkName(networkName: string): NetworkId { case 'testnet-1': case 'testnet-2': case 'docker': - case 'docker-1709894432': + case 'docker-1711022286': return NetworkId.Testnet default: return NetworkId.Custom diff --git a/packages/shared/lib/core/wallet/utils/outputs/preprocessGroupedOutputs.ts b/packages/shared/lib/core/wallet/utils/outputs/preprocessGroupedOutputs.ts index 343218bd9ae..c25b510fbf3 100644 --- a/packages/shared/lib/core/wallet/utils/outputs/preprocessGroupedOutputs.ts +++ b/packages/shared/lib/core/wallet/utils/outputs/preprocessGroupedOutputs.ts @@ -1,10 +1,9 @@ -import { CommonOutput, OutputData, OutputResponse, UTXOInput } from '@iota/sdk/out/types' +import { CommonOutput, OutputData, OutputWithMetadata, UTXOInput } from '@iota/sdk/out/types' import { IWalletState } from '@core/wallet/interfaces' import { InclusionState, ActivityDirection } from '../../enums' import { IProcessedTransaction, IWrappedOutput } from '../../interfaces' import { getRecipientAddressFromOutput } from './getRecipientAddressFromOutput' import { getSenderAddressFromInputs } from '../transactions' -import { getOutputIdFromTransactionIdAndIndex } from './getOutputIdFromTransactionIdAndIndex' import { getUnixTimestampFromNodeInfoAndSlotIndex, nodeInfoProtocolParameters } from '@core/network' import { get } from 'svelte/store' import { MILLISECONDS_PER_SECOND } from '@core/utils' @@ -12,14 +11,11 @@ import { MILLISECONDS_PER_SECOND } from '@core/utils' // TODO(2.0) Fix all usages export function preprocessGroupedOutputs( outputDatas: OutputData[], - transactionInputs: OutputResponse[], + transactionInputs: OutputWithMetadata[], wallet: IWalletState ): IProcessedTransaction { const transactionMetadata = outputDatas[0]?.metadata - const wrappedInputs = convertTransactionOutputResponsesToWrappedOutputs( - transactionMetadata?.included.transactionId, - transactionInputs - ) + const wrappedInputs = convertTransactionOutputResponsesToWrappedOutputs(transactionInputs) const utxoInputs = getUtxoInputsFromWrappedInputs(wrappedInputs) const direction = getDirectionForOutputs(outputDatas, wrappedInputs, wallet.depositAddress) const wrappedOutputs = outputDatas.map((outputData) => ({ @@ -75,25 +71,18 @@ function getDirectionForOutputs( } } -function convertTransactionOutputResponsesToWrappedOutputs( - transactionId: string, - outputResponses: OutputResponse[] -): IWrappedOutput[] { - return outputResponses.map((outputResponse) => - convertTransactionOutputResponseToWrappedOutput(transactionId, outputResponse) - ) +function convertTransactionOutputResponsesToWrappedOutputs(outputResponses: OutputWithMetadata[]): IWrappedOutput[] { + return outputResponses.map((outputResponse) => convertTransactionOutputResponseToWrappedOutput(outputResponse)) } -function convertTransactionOutputResponseToWrappedOutput( - transactionId: string, - outputResponse: OutputResponse -): IWrappedOutput { - const outputId = getOutputIdFromTransactionIdAndIndex(transactionId, outputResponse.metadata.outputIndex) - return { outputId, output: outputResponse.output, metadata: outputResponse.metadata } +function convertTransactionOutputResponseToWrappedOutput(outputResponse: OutputWithMetadata): IWrappedOutput { + return { + outputId: outputResponse.metadata.outputId, + output: outputResponse.output, + metadata: outputResponse.metadata, + } } function getUtxoInputsFromWrappedInputs(wrappedInputs: IWrappedOutput[]): UTXOInput[] { - return ( - wrappedInputs?.map((input) => new UTXOInput(input.metadata?.transactionId, input.metadata?.outputIndex)) ?? [] - ) + return wrappedInputs?.map((input) => UTXOInput.fromOutputId(input.outputId)) ?? [] } diff --git a/packages/shared/lib/core/wallet/utils/outputs/preprocessOutgoingTransaction.ts b/packages/shared/lib/core/wallet/utils/outputs/preprocessOutgoingTransaction.ts index c0a17230174..ee2f605550a 100644 --- a/packages/shared/lib/core/wallet/utils/outputs/preprocessOutgoingTransaction.ts +++ b/packages/shared/lib/core/wallet/utils/outputs/preprocessOutgoingTransaction.ts @@ -15,11 +15,11 @@ export async function preprocessOutgoingTransaction( const outputs = convertTransactionsOutputTypesToWrappedOutputs(transactionId, regularTransactionEssence.outputs) const direction = getDirectionFromOutgoingTransaction(outputs, wallet.depositAddress) - const utxoInputs = regularTransactionEssence.inputs.map((i) => i as UTXOInput) const inputIds = await Promise.all( - utxoInputs.map((input) => { - const transactionId = input.transactionId - const transactionOutputIndex = input.transactionOutputIndex + regularTransactionEssence.inputs.map((input) => { + const _input = input as UTXOInput + const transactionId = _input.transactionId + const transactionOutputIndex = _input.transactionOutputIndex return computeOutputId(transactionId, transactionOutputIndex) }) ) @@ -33,7 +33,6 @@ export async function preprocessOutgoingTransaction( time: new Date(Number(transaction.timestamp)), inclusionState: transaction.inclusionState, wrappedInputs: inputs, - utxoInputs, } } From 4d28457ca318902a46ec915172c39988219fe5c5 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Fri, 22 Mar 2024 09:29:33 +0100 Subject: [PATCH 2/3] feat: stop generating txs out of outputs --- .../actions/activities/generateAndStoreActivitiesForWallet.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/shared/lib/core/wallet/actions/activities/generateAndStoreActivitiesForWallet.ts b/packages/shared/lib/core/wallet/actions/activities/generateAndStoreActivitiesForWallet.ts index 8e8cb8c2fb8..181d241a91a 100644 --- a/packages/shared/lib/core/wallet/actions/activities/generateAndStoreActivitiesForWallet.ts +++ b/packages/shared/lib/core/wallet/actions/activities/generateAndStoreActivitiesForWallet.ts @@ -2,7 +2,6 @@ import { IWalletState } from '@core/wallet/interfaces' import { setOutgoingAsyncActivitiesToClaimed } from '../setOutgoingAsyncActivitiesToClaimed' import { preprocessTransactionsForWallet } from './preprocessTransactionsForWallet' -import { preprocessOutputsForWallet } from './preprocessOutputsForWallet' import { linkTransactionsWithClaimingTransactions } from './linkTransactionsWithClaimingTransactions' import { hideActivitiesForFoundries } from './hideActivitiesForFoundries' import { generateActivitiesFromProcessedTransactions } from './generateActivitiesFromProcessedTransactions' @@ -13,7 +12,7 @@ export async function generateAndStoreActivitiesForWallet(wallet: IWalletState): // Step 1: process wallet transactions and outputs into processed transactions const processedTransactions = [ ...(await preprocessTransactionsForWallet(wallet)), - ...(await preprocessOutputsForWallet(wallet)), + // ...(await preprocessOutputsForWallet(wallet)), ] // Step 2: link transactions with corresponding claiming transactions From 71f88e7aeac24bb1285bb47bb675b111f849ad69 Mon Sep 17 00:00:00 2001 From: cpl121 Date: Fri, 22 Mar 2024 17:44:13 +0100 Subject: [PATCH 3/3] fix: tx history: include account output in average txs --- .../preprocessTransactionsForWallet.ts | 14 +++- .../generateActivity/generateActivities.ts | 5 +- .../generateActivitiesFromBasicOutputs.ts | 76 ++++++++++--------- .../wallet/utils/outputs/computeOutputId.ts | 2 +- .../lib/core/wallet/utils/outputs/index.ts | 1 + .../outputs/preprocessIncomingTransaction.ts | 57 ++++++++++++++ .../outputs/preprocessOutgoingTransaction.ts | 25 +++--- .../getDirectionFromOutgoingTransaction.ts | 9 +-- 8 files changed, 131 insertions(+), 58 deletions(-) create mode 100644 packages/shared/lib/core/wallet/utils/outputs/preprocessIncomingTransaction.ts diff --git a/packages/shared/lib/core/wallet/actions/activities/preprocessTransactionsForWallet.ts b/packages/shared/lib/core/wallet/actions/activities/preprocessTransactionsForWallet.ts index fb072035e2c..f1ff39c8341 100644 --- a/packages/shared/lib/core/wallet/actions/activities/preprocessTransactionsForWallet.ts +++ b/packages/shared/lib/core/wallet/actions/activities/preprocessTransactionsForWallet.ts @@ -1,11 +1,10 @@ import { IWalletState } from '@core/wallet/interfaces' -import { preprocessOutgoingTransaction } from '../../utils' +import { preprocessIncomingTransaction, preprocessOutgoingTransaction } from '../../utils' import { IProcessedTransaction } from '../../interfaces/processed-transaction.interface' export async function preprocessTransactionsForWallet(wallet: IWalletState): Promise { - const transactions = await wallet.transactions() - const processedTransactions: IProcessedTransaction[] = [] + const transactions = await wallet.transactions() for (const transaction of transactions) { try { @@ -15,5 +14,14 @@ export async function preprocessTransactionsForWallet(wallet: IWalletState): Pro console.error(err) } } + const incomingTransactions = await wallet.incomingTransactions() + for (const incomingTransaction of incomingTransactions) { + try { + const processedTransaction = preprocessIncomingTransaction(incomingTransaction) + processedTransactions.push(processedTransaction) + } catch (err) { + console.error(err) + } + } return processedTransactions } diff --git a/packages/shared/lib/core/wallet/utils/generateActivity/generateActivities.ts b/packages/shared/lib/core/wallet/utils/generateActivity/generateActivities.ts index c6904ab32c2..7e54cc2ce2c 100644 --- a/packages/shared/lib/core/wallet/utils/generateActivity/generateActivities.ts +++ b/packages/shared/lib/core/wallet/utils/generateActivity/generateActivities.ts @@ -47,8 +47,11 @@ async function generateActivitiesFromProcessedTransactionsWithInputs( activities.push(...nftActivities) } + const containsAccountInInputs = wrappedInputs.some((input) => input.output.type === OutputType.Account) const containsAccountActivity = - outputs.some((output) => output.output.type === OutputType.Account) && !containsFoundryActivity + !containsAccountInInputs && + outputs.some((output) => output.output.type === OutputType.Account) && + !containsFoundryActivity if (containsAccountActivity) { const accountActivities = await generateActivitiesFromAccountOutputs(processedTransaction, wallet) activities.push(...accountActivities) diff --git a/packages/shared/lib/core/wallet/utils/generateActivity/generateActivitiesFromBasicOutputs.ts b/packages/shared/lib/core/wallet/utils/generateActivity/generateActivitiesFromBasicOutputs.ts index d08cd5a7067..2554635b9d4 100644 --- a/packages/shared/lib/core/wallet/utils/generateActivity/generateActivitiesFromBasicOutputs.ts +++ b/packages/shared/lib/core/wallet/utils/generateActivity/generateActivitiesFromBasicOutputs.ts @@ -29,54 +29,56 @@ export async function generateActivitiesFromBasicOutputs( const burnedNftInputs = getBurnedNftInputs(processedTransaction) for (const basicOutput of basicOutputs) { let activity: Activity + const isRemainder = basicOutput.remainder - const isSelfTransaction = processedTransaction.direction === ActivityDirection.SelfTransaction const burnedNftInputIndex = burnedNftInputs.findIndex( (input) => input.output.amount === basicOutput.output.amount ) const burnedNativeToken = burnedNftInputIndex < 0 ? getBurnedNativeTokens(processedTransaction) : undefined - if (isSelfTransaction && burnedNftInputIndex >= 0) { - const wrappedInput = burnedNftInputs[burnedNftInputIndex] - const nftInput = wrappedInput.output as NftOutput - activity = await generateSingleNftActivity( - wallet, - { - action: ActivityAction.Burn, + if (!isRemainder) { + if (burnedNftInputIndex >= 0) { + const wrappedInput = burnedNftInputs[burnedNftInputIndex] + const nftInput = wrappedInput.output as NftOutput + activity = await generateSingleNftActivity( + wallet, + { + action: ActivityAction.Burn, + processedTransaction, + wrappedOutput: basicOutput, + }, + getNftId(nftInput.nftId, wrappedInput.outputId) + ) + const nft = buildNftFromNftOutput(wrappedInput, wallet.depositAddress, false) + addOrUpdateNftInAllWalletNfts(wallet.id, nft) + + burnedNftInputs.splice(burnedNftInputIndex, 1) + } else if (burnedNativeToken) { + activity = await generateSingleBasicActivity( + wallet, + { + action: ActivityAction.Burn, + processedTransaction, + wrappedOutput: basicOutput, + }, + burnedNativeToken.assetId, + burnedNativeToken.amount + ) + } else if (isConsolidation(basicOutput, processedTransaction)) { + activity = await generateSingleConsolidationActivity(wallet, { + action: ActivityAction.Send, processedTransaction, wrappedOutput: basicOutput, - }, - getNftId(nftInput.nftId, wrappedInput.outputId) - ) - const nft = buildNftFromNftOutput(wrappedInput, wallet.depositAddress, false) - addOrUpdateNftInAllWalletNfts(wallet.id, nft) - - burnedNftInputs.splice(burnedNftInputIndex, 1) - } else if (isSelfTransaction && burnedNativeToken) { - activity = await generateSingleBasicActivity( - wallet, - { - action: ActivityAction.Burn, + }) + } else { + activity = await generateSingleBasicActivity(wallet, { + action: ActivityAction.Send, processedTransaction, wrappedOutput: basicOutput, - }, - burnedNativeToken.assetId, - burnedNativeToken.amount - ) - } else if (isSelfTransaction && isConsolidation(basicOutput, processedTransaction)) { - activity = await generateSingleConsolidationActivity(wallet, { - action: ActivityAction.Send, - processedTransaction, - wrappedOutput: basicOutput, - }) - } else { - activity = await generateSingleBasicActivity(wallet, { - action: ActivityAction.Send, - processedTransaction, - wrappedOutput: basicOutput, - }) + }) + } + activities.push(activity) } - activities.push(activity) } return activities } diff --git a/packages/shared/lib/core/wallet/utils/outputs/computeOutputId.ts b/packages/shared/lib/core/wallet/utils/outputs/computeOutputId.ts index 1727a96081e..7c95944ed0a 100644 --- a/packages/shared/lib/core/wallet/utils/outputs/computeOutputId.ts +++ b/packages/shared/lib/core/wallet/utils/outputs/computeOutputId.ts @@ -1,6 +1,6 @@ import { TransactionId, OutputId } from '@iota/sdk/out/types' import { api } from '@core/api' -export function computeOutputId(id: TransactionId, index: number): Promise { +export function computeOutputId(id: TransactionId, index: number): OutputId { return api.computeOutputId(id, index) } diff --git a/packages/shared/lib/core/wallet/utils/outputs/index.ts b/packages/shared/lib/core/wallet/utils/outputs/index.ts index 55778a6cb4e..625a9c13668 100644 --- a/packages/shared/lib/core/wallet/utils/outputs/index.ts +++ b/packages/shared/lib/core/wallet/utils/outputs/index.ts @@ -21,3 +21,4 @@ export * from './preprocessOutgoingTransaction' export * from './getOutputIdFromTransactionIdAndIndex' export * from './getRequiredStorageDepositForMinimalBasicOutput' export * from './getSerialNumberFromAccountAddress' +export * from './preprocessIncomingTransaction' diff --git a/packages/shared/lib/core/wallet/utils/outputs/preprocessIncomingTransaction.ts b/packages/shared/lib/core/wallet/utils/outputs/preprocessIncomingTransaction.ts new file mode 100644 index 00000000000..448b2715aac --- /dev/null +++ b/packages/shared/lib/core/wallet/utils/outputs/preprocessIncomingTransaction.ts @@ -0,0 +1,57 @@ +import { IProcessedTransaction, IWrappedOutput } from '../../interfaces' +import { Output, OutputType, OutputWithMetadata, TransactionWithMetadata, UTXOInput } from '@iota/sdk/out/types' +// import { computeOutputId } from './computeOutputId' +import { getOutputIdFromTransactionIdAndIndex } from './getOutputIdFromTransactionIdAndIndex' +import { ActivityDirection } from '../../enums' + +export function preprocessIncomingTransaction(transaction: TransactionWithMetadata): IProcessedTransaction { + const regularTransactionEssence = transaction.payload.transaction + const transactionId = transaction?.transactionId?.toString() + + const outputs = convertTransactionsOutputTypesToWrappedOutputs(transactionId, regularTransactionEssence.outputs) + + const utxoInputs = regularTransactionEssence.inputs.map((i) => i as UTXOInput) + // const inputIds = utxoInputs.map((input) => { + // const transactionId = input.transactionId + // const transactionOutputIndex = input.transactionOutputIndex + // return computeOutputId(transactionId, transactionOutputIndex) + // }) + // const inputs = await Promise.all(inputIds.map((inputId) => wallet.getOutput(inputId))) + + return { + outputs: outputs, + transactionId, + direction: ActivityDirection.Incoming, + time: new Date(Number(transaction.timestamp)), + inclusionState: transaction.inclusionState, + wrappedInputs: [], + // wrappedInputs: inputs, + utxoInputs, + } +} + +function convertTransactionsOutputTypesToWrappedOutputs( + transactionId: string, + outputTypes: Output[] +): IWrappedOutput[] { + return outputTypes.map((outputType, index) => + convertTransactionOutputTypeToWrappedOutput(transactionId, index, outputType) + ) +} + +function convertTransactionOutputTypeToWrappedOutput( + transactionId: string, + index: number, + outputType: Output +): IWrappedOutput { + const outputId = getOutputIdFromTransactionIdAndIndex(transactionId, index) + OutputWithMetadata + return { + outputId, + output: outputType, + remainder: + index === 0 || (outputType.type !== OutputType.Basic && outputType.type !== OutputType.Account) + ? false + : true, // when sending prepared output in the resulting transactions outputs array it will always be first output(index = 0) + } +} diff --git a/packages/shared/lib/core/wallet/utils/outputs/preprocessOutgoingTransaction.ts b/packages/shared/lib/core/wallet/utils/outputs/preprocessOutgoingTransaction.ts index ee2f605550a..b49ab348049 100644 --- a/packages/shared/lib/core/wallet/utils/outputs/preprocessOutgoingTransaction.ts +++ b/packages/shared/lib/core/wallet/utils/outputs/preprocessOutgoingTransaction.ts @@ -1,5 +1,5 @@ import { IProcessedTransaction, IWrappedOutput } from '../../interfaces' -import { Output, OutputType, TransactionWithMetadata, UTXOInput } from '@iota/sdk/out/types' +import { Output, OutputType, OutputWithMetadata, TransactionWithMetadata, UTXOInput } from '@iota/sdk/out/types' import { computeOutputId } from './computeOutputId' import { getOutputIdFromTransactionIdAndIndex } from './getOutputIdFromTransactionIdAndIndex' import { getDirectionFromOutgoingTransaction } from '../transactions' @@ -14,15 +14,13 @@ export async function preprocessOutgoingTransaction( const outputs = convertTransactionsOutputTypesToWrappedOutputs(transactionId, regularTransactionEssence.outputs) - const direction = getDirectionFromOutgoingTransaction(outputs, wallet.depositAddress) - const inputIds = await Promise.all( - regularTransactionEssence.inputs.map((input) => { - const _input = input as UTXOInput - const transactionId = _input.transactionId - const transactionOutputIndex = _input.transactionOutputIndex - return computeOutputId(transactionId, transactionOutputIndex) - }) - ) + const direction = getDirectionFromOutgoingTransaction(regularTransactionEssence.outputs, await wallet.address()) + const utxoInputs = regularTransactionEssence.inputs.map((i) => i as UTXOInput) + const inputIds = utxoInputs.map((input) => { + const transactionId = input.transactionId + const transactionOutputIndex = input.transactionOutputIndex + return computeOutputId(transactionId, transactionOutputIndex) + }) const inputs = await Promise.all(inputIds.map((inputId) => wallet.getOutput(inputId))) @@ -33,6 +31,7 @@ export async function preprocessOutgoingTransaction( time: new Date(Number(transaction.timestamp)), inclusionState: transaction.inclusionState, wrappedInputs: inputs, + utxoInputs, } } @@ -51,9 +50,13 @@ function convertTransactionOutputTypeToWrappedOutput( outputType: Output ): IWrappedOutput { const outputId = getOutputIdFromTransactionIdAndIndex(transactionId, index) + OutputWithMetadata return { outputId, output: outputType, - remainder: index === 0 || outputType.type !== OutputType.Basic ? false : true, // when sending prepared output in the resulting transactions outputs array it will always be first output(index = 0) + remainder: + index === 0 || (outputType.type !== OutputType.Basic && outputType.type !== OutputType.Account) + ? false + : true, // when sending prepared output in the resulting transactions outputs array it will always be first output(index = 0) } } diff --git a/packages/shared/lib/core/wallet/utils/transactions/getDirectionFromOutgoingTransaction.ts b/packages/shared/lib/core/wallet/utils/transactions/getDirectionFromOutgoingTransaction.ts index 6182044ba1a..094bd920052 100644 --- a/packages/shared/lib/core/wallet/utils/transactions/getDirectionFromOutgoingTransaction.ts +++ b/packages/shared/lib/core/wallet/utils/transactions/getDirectionFromOutgoingTransaction.ts @@ -1,15 +1,14 @@ -import { IWrappedOutput } from '../../interfaces' import { getRecipientAddressFromOutput } from '../outputs/getRecipientAddressFromOutput' import { ActivityDirection } from '@core/wallet/enums' -import { CommonOutput } from '@iota/sdk/out/types' +import { CommonOutput, Output } from '@iota/sdk/out/types' export function getDirectionFromOutgoingTransaction( - wrappedOutputs: IWrappedOutput[], + outputs: Output[], walletDepositAddress: string ): ActivityDirection { // Check if any output is not destined for the wallet - const containsNonWalletRecipient = wrappedOutputs.some((outputData) => { - const outputRecipient = getRecipientAddressFromOutput(outputData.output as CommonOutput) + const containsNonWalletRecipient = outputs.some((output) => { + const outputRecipient = getRecipientAddressFromOutput(output as CommonOutput) return walletDepositAddress !== outputRecipient })