diff --git a/api/src/models/db/networkType.ts b/api/src/models/db/networkType.ts index 1ed69e50a..1ab097ec1 100644 --- a/api/src/models/db/networkType.ts +++ b/api/src/models/db/networkType.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ const LEGACY_MAINNET = "legacy-mainnet"; const CHRYSALIS_MAINNET = "chrysalis-mainnet"; -const MAINNET = "mainnet"; +export const MAINNET = "mainnet"; const DEVNET = "devnet"; export const SHIMMER = "shimmer"; const TESTNET = "testnet"; diff --git a/api/src/routes/stardust/transactionhistory/download/post.ts b/api/src/routes/stardust/transactionhistory/download/post.ts index 355a9a7c8..cce621140 100644 --- a/api/src/routes/stardust/transactionhistory/download/post.ts +++ b/api/src/routes/stardust/transactionhistory/download/post.ts @@ -1,4 +1,4 @@ -import { OutputResponse, INodeInfoBaseToken, CommonOutput } from "@iota/sdk"; +import { CommonOutput, INodeInfoBaseToken, OutputResponse } from "@iota/sdk"; import JSZip from "jszip"; import moment from "moment"; import { ServiceFactory } from "../../../../factories/serviceFactory"; @@ -8,6 +8,8 @@ import { ITransactionHistoryDownloadBody } from "../../../../models/api/stardust import { ITransactionHistoryRequest } from "../../../../models/api/stardust/chronicle/ITransactionHistoryRequest"; import { ITransactionHistoryItem } from "../../../../models/api/stardust/chronicle/ITransactionHistoryResponse"; import { IConfiguration } from "../../../../models/configuration/IConfiguration"; +import { INetwork } from "../../../../models/db/INetwork"; +import { MAINNET } from "../../../../models/db/networkType"; import { STARDUST } from "../../../../models/db/protocolVersion"; import { NetworkService } from "../../../../services/networkService"; import { ChronicleService } from "../../../../services/stardust/chronicleService"; @@ -20,6 +22,7 @@ export interface ITransactionHistoryRecord { isGenesisByDate: boolean; isSpent: boolean; transactionId: string; + outputIdFromSupplyIncrease?: string; timestamp: number; dateFormatted: string; balanceChange: number; @@ -27,6 +30,8 @@ export interface ITransactionHistoryRecord { outputs: OutputWithDetails[]; } +const STARDUST_GENESIS_MILESTONE = 7669900; + /** * Download the transaction history from chronicle stardust. * @param _ The configuration. @@ -73,14 +78,21 @@ export async function post( }); const tokenInfo = nodeInfoService.getNodeInfo().baseToken; - const transactions = getTransactionHistoryRecords(groupOutputsByTransactionId(fulfilledOutputs), tokenInfo); + const transactions = getTransactionHistoryRecords(groupOutputsByTransactionId(fulfilledOutputs), tokenInfo, networkConfig); const headers = ["Timestamp", "TransactionId", "Balance changes"]; let csvContent = `${headers.join(",")}\n`; for (const transaction of transactions) { - const row = [transaction.dateFormatted, transaction.transactionId, transaction.balanceChangeFormatted].join(","); + let transactionCell = transaction.transactionId; + if (transaction.isGenesisByDate) { + transactionCell = `Stardust Genesis (Chrysalis): ${transactionCell}`; + if (transaction.outputIdFromSupplyIncrease) { + transactionCell = `Supply Increase Output: ${transaction.outputIdFromSupplyIncrease}`; + } + } + const row = [transaction.dateFormatted, transactionCell, transaction.balanceChangeFormatted].join(","); csvContent += `${row}\n`; } @@ -140,21 +152,26 @@ export const groupOutputsByTransactionId = (outputsWithDetails: OutputWithDetail export const getTransactionHistoryRecords = ( transactionIdToOutputs: Map, tokenInfo: INodeInfoBaseToken, + networkConfig: INetwork, ): ITransactionHistoryRecord[] => { const calculatedTransactions: ITransactionHistoryRecord[] = []; for (const [transactionId, outputs] of transactionIdToOutputs.entries()) { const lastOutputTime = Math.max(...outputs.map((t) => t.milestoneTimestamp)); const balanceChange = calculateBalanceChange(outputs); - - const isGenesisByDate = outputs.map((t) => t.milestoneTimestamp).includes(0); - const isSpent = balanceChange <= 0; + const isGenesisByDate = outputs.some((output) => output.milestoneIndex === STARDUST_GENESIS_MILESTONE); + + let outputIdFromSupplyIncrease; + if (isGenesisByDate) { + outputIdFromSupplyIncrease = getStardustGenesisOutputId(outputs, networkConfig, transactionId); + } calculatedTransactions.push({ isGenesisByDate, isSpent, transactionId, + outputIdFromSupplyIncrease, timestamp: lastOutputTime, dateFormatted: moment(lastOutputTime * 1000).format("YYYY-MM-DD HH:mm:ss"), balanceChange, @@ -165,6 +182,28 @@ export const getTransactionHistoryRecords = ( return calculatedTransactions; }; +/** + * Get the output id from the stardust genesis. + * @param outputs List of outputs related to transaction + * @param networkConfig Network configuration + * @param transactionId Current trancaction + * @returns The output id from the stardust genesis or undefined. + */ +function getStardustGenesisOutputId(outputs: OutputWithDetails[], networkConfig: INetwork, transactionId: string): string | undefined { + const STARDUST_SUPPLY_INCREASE_OUTPUT_TICKER = "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb18"; + + const outputFromStardustGenesis = outputs.find((output) => { + if ( + networkConfig.network === MAINNET && + output.milestoneIndex === STARDUST_GENESIS_MILESTONE && + transactionId.includes(STARDUST_SUPPLY_INCREASE_OUTPUT_TICKER) + ) { + return true; + } + }); + return outputFromStardustGenesis?.outputId; +} + export const calculateBalanceChange = (outputs: OutputWithDetails[]) => { let totalAmount = 0; diff --git a/client/src/app/components/stardust/history/TransactionHistory.tsx b/client/src/app/components/stardust/history/TransactionHistory.tsx index 564c2a736..d1e8e954a 100644 --- a/client/src/app/components/stardust/history/TransactionHistory.tsx +++ b/client/src/app/components/stardust/history/TransactionHistory.tsx @@ -50,17 +50,7 @@ const TransactionHistory: React.FC = ({ network, addres {transactions?.map((c, idx) => ( - + ))} diff --git a/client/src/app/components/stardust/history/TransactionIdView.tsx b/client/src/app/components/stardust/history/TransactionIdView.tsx index 7b32149ef..9e339f9c3 100644 --- a/client/src/app/components/stardust/history/TransactionIdView.tsx +++ b/client/src/app/components/stardust/history/TransactionIdView.tsx @@ -1,5 +1,6 @@ import React from "react"; -import { STARDUST_SUPPLY_INCREASE_TRANSACTION_ID } from "~/helpers/stardust/transactionsHelper"; +import { Link } from "react-router-dom"; +import { STARDUST_SUPPLY_INCREASE_OUTPUT_TICKER } from "~/helpers/stardust/transactionsHelper"; import TruncatedId from "../TruncatedId"; import Tooltip from "../../Tooltip"; @@ -10,21 +11,23 @@ export interface ITransactionIdProps { } const TransactionIdView: React.FC = ({ transactionId, isTransactionFromStardustGenesis, transactionLink }) => { + if (isTransactionFromStardustGenesis && transactionId.includes(STARDUST_SUPPLY_INCREASE_OUTPUT_TICKER)) { + return ( + + Supply Increase + + ); + } + return ( <> - {isTransactionFromStardustGenesis && transactionId.includes(STARDUST_SUPPLY_INCREASE_TRANSACTION_ID) ? ( - Stardust Genesis - ) : ( - <> - - {isTransactionFromStardustGenesis && ( - - - warning - - - )} - + + {isTransactionFromStardustGenesis && ( + + + warning + + )} ); diff --git a/client/src/app/components/stardust/history/transactionHistoryUtils.ts b/client/src/app/components/stardust/history/transactionHistoryUtils.ts index a281a7f29..855583f6f 100644 --- a/client/src/app/components/stardust/history/transactionHistoryUtils.ts +++ b/client/src/app/components/stardust/history/transactionHistoryUtils.ts @@ -3,7 +3,7 @@ import moment from "moment/moment"; import { DateHelper } from "~helpers/dateHelper"; import { OutputWithDetails } from "~helpers/hooks/useAddressHistory"; -import { STARDUST_SUPPLY_INCREASE_TRANSACTION_ID, TransactionsHelper } from "~helpers/stardust/transactionsHelper"; +import { STARDUST_SUPPLY_INCREASE_OUTPUT_TICKER, TransactionsHelper } from "~helpers/stardust/transactionsHelper"; import { formatAmount } from "~helpers/stardust/valueFormatHelper"; import { CHRYSALIS_MAINNET } from "~models/config/networkType"; @@ -64,12 +64,17 @@ export const getTransactionHistoryRecords = ( const isGenesisByDate = outputs.map((t) => t.milestoneTimestamp).some((milestoneTimestamp) => milestoneTimestamp === 0); - const milestoneIndexes = outputs.map((t) => t.milestoneIndex); - const isTransactionFromStardustGenesis = milestoneIndexes.some((milestoneIndex) => - TransactionsHelper.isTransactionFromIotaStardustGenesis(network, milestoneIndex), - ); + let stardustGenesisOutputId; + const isTransactionFromStardustGenesis = outputs.some(({ milestoneIndex, outputId }) => { + const isGenesis = TransactionsHelper.isTransactionFromIotaStardustGenesis(network, milestoneIndex); + if (isGenesis) { + stardustGenesisOutputId = outputId; + } + + return isGenesis; + }); - const transactionLink = getTransactionLink(network, transactionId, isTransactionFromStardustGenesis); + const transactionLink = getTransactionLink(network, transactionId, isTransactionFromStardustGenesis, stardustGenesisOutputId); const isSpent = balanceChange <= 0; @@ -106,8 +111,19 @@ export const calculateBalanceChange = (outputs: OutputWithDetails[]) => { }, 0); }; -export const getTransactionLink = (network: string, transactionId: string, isTransactionFromStardustGenesis: boolean) => { - return isTransactionFromStardustGenesis && !transactionId.includes(STARDUST_SUPPLY_INCREASE_TRANSACTION_ID) - ? `/${CHRYSALIS_MAINNET}/search/${transactionId}` - : `/${network}/transaction/${transactionId}`; +export const getTransactionLink = ( + network: string, + transactionId: string, + isTransactionFromStardustGenesis: boolean, + outputId?: string, +) => { + if (isTransactionFromStardustGenesis && transactionId.includes(STARDUST_SUPPLY_INCREASE_OUTPUT_TICKER)) { + return `/${network}/output/${outputId}`; + } + + if (isTransactionFromStardustGenesis && !transactionId.includes(STARDUST_SUPPLY_INCREASE_OUTPUT_TICKER)) { + return `/${CHRYSALIS_MAINNET}/search/${transactionId}`; + } + + return `/${network}/transaction/${transactionId}`; }; diff --git a/client/src/app/routes/stardust/OutputPage.tsx b/client/src/app/routes/stardust/OutputPage.tsx index 4ec091e8d..deb6ba688 100644 --- a/client/src/app/routes/stardust/OutputPage.tsx +++ b/client/src/app/routes/stardust/OutputPage.tsx @@ -51,7 +51,7 @@ const OutputPage: React.FC> = ({ } = outputMetadata ?? {}; const isTransactionFromStardustGenesis = TransactionsHelper.isTransactionFromIotaStardustGenesis(network, milestoneIndexBooked ?? 0); - const transactionLink = getTransactionLink(network, transactionId ?? "", isTransactionFromStardustGenesis); + const transactionLink = getTransactionLink(network, transactionId ?? "", isTransactionFromStardustGenesis, outputId); return ( (output && ( diff --git a/client/src/helpers/stardust/transactionsHelper.ts b/client/src/helpers/stardust/transactionsHelper.ts index c3dc20a19..2419c8bdf 100644 --- a/client/src/helpers/stardust/transactionsHelper.ts +++ b/client/src/helpers/stardust/transactionsHelper.ts @@ -53,7 +53,7 @@ const HEX_PARTICIPATE = "0x5041525449434950415445"; */ export const STARDUST_GENESIS_MILESTONE = 7669900; -export const STARDUST_SUPPLY_INCREASE_TRANSACTION_ID = "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb18"; +export const STARDUST_SUPPLY_INCREASE_OUTPUT_TICKER = "0xb191c4bc825ac6983789e50545d5ef07a1d293a98ad974fc9498cb18"; export class TransactionsHelper { public static async getInputsAndOutputs(