Skip to content
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

feat: mark expired transactions #1006

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const TransactionCard: React.FC<ITransactionEntryProps> = ({
isSpent,
isFormattedAmounts,
setIsFormattedAmounts,
isExpired,
}) => {
const valueView = (
<span className="pointer margin-r-5" onClick={() => setIsFormattedAmounts(!isFormattedAmounts)}>
Expand All @@ -33,6 +34,7 @@ const TransactionCard: React.FC<ITransactionEntryProps> = ({
transactionId={transactionId}
isTransactionFromStardustGenesis={isTransactionFromStardustGenesis}
transactionLink={transactionLink}
isTxExpired={isExpired}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export interface ITransactionEntryProps {
*/
isSpent: boolean;

/**
* Is the transaction expired.
*/
isExpired: boolean;

/**
* Are the amounts formatted.
*/
Expand Down
28 changes: 28 additions & 0 deletions client/src/app/components/stardust/history/TransactionHistory.scss
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@
color: var(--expanded-color);
}
}

.transaction-indicators {
display: flex;

> * {
margin-left: 4px;
}

.tx-indicator {
@include font-size(16px);

vertical-align: sub;
}
}
}

td,
Expand Down Expand Up @@ -138,6 +152,20 @@
color: var(--expanded-color);
}
}

.transaction-indicators {
display: flex;

> * {
margin-left: 4px;
}

.tx-indicator {
@include font-size(20px);

vertical-align: sub;
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const TransactionHistory: React.FC<TransactionHistoryProps> = ({ network, addres
isSpent={c.isSpent}
isFormattedAmounts={isFormattedAmounts}
setIsFormattedAmounts={setIsFormattedAmounts}
isExpired={c.isExpired}
/>
</React.Fragment>
))}
Expand All @@ -81,6 +82,7 @@ const TransactionHistory: React.FC<TransactionHistoryProps> = ({ network, addres
isSpent={c.isSpent}
isFormattedAmounts={isFormattedAmounts}
setIsFormattedAmounts={setIsFormattedAmounts}
isExpired={c.isExpired}
/>
</React.Fragment>
);
Expand Down
47 changes: 40 additions & 7 deletions client/src/app/components/stardust/history/TransactionIdView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,55 @@ export interface ITransactionIdProps {
transactionId: string;
isTransactionFromStardustGenesis: boolean;
transactionLink: string;
isTxExpired?: boolean;
}

const TransactionIdView: React.FC<ITransactionIdProps> = ({ transactionId, isTransactionFromStardustGenesis, transactionLink }) => {
interface ITxIndicator {
icon: string;
message: string;
condition?: boolean;
}

const TX_EXPIRED_MESSAGE = "Transaction has expired.";
const CHRYSALIS_TX_MESSAGE = "This link opens the transaction on Chrysalis Mainnet";

const TransactionIdView: React.FC<ITransactionIdProps> = ({
transactionId,
isTransactionFromStardustGenesis,
transactionLink,
isTxExpired,
}) => {
const indicators: ITxIndicator[] = [
{
icon: "warning",
message: CHRYSALIS_TX_MESSAGE,
condition: isTransactionFromStardustGenesis,
},
{
icon: "hourglass_bottom",
message: TX_EXPIRED_MESSAGE,
condition: isTxExpired,
},
];

return (
<>
{isTransactionFromStardustGenesis && transactionId.includes(STARDUST_SUPPLY_INCREASE_TRANSACTION_ID) ? (
<span>Stardust Genesis</span>
) : (
<>
<TruncatedId id={transactionId} link={transactionLink} />
{isTransactionFromStardustGenesis && (
<Tooltip tooltipContent="This link opens the transaction on Chrysalis Mainnet" childrenClass="row middle">
<span className="material-icons" style={{ fontSize: "14px" }}>
warning
</span>
</Tooltip>
{indicators.length > 0 && (
<div className="transaction-indicators">
{indicators.map(
({ icon, message, condition }, index) =>
condition && (
<Tooltip key={index} tooltipContent={message} childrenClass="row middle">
<span className="material-icons tx-indicator">{icon}</span>
</Tooltip>
),
)}
</div>
)}
</>
)}
Expand Down
2 changes: 2 additions & 0 deletions client/src/app/components/stardust/history/TransactionRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const TransactionRow: React.FC<ITransactionEntryProps> = ({
isSpent,
isFormattedAmounts,
setIsFormattedAmounts,
isExpired,
}) => {
const valueView = (
<span className="pointer" onClick={() => setIsFormattedAmounts(!isFormattedAmounts)}>
Expand All @@ -29,6 +30,7 @@ const TransactionRow: React.FC<ITransactionEntryProps> = ({
transactionId={transactionId}
isTransactionFromStardustGenesis={isTransactionFromStardustGenesis}
transactionLink={transactionLink}
isTxExpired={isExpired}
/>
</div>
</td>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommonOutput, INodeInfoBaseToken } from "@iota/sdk-wasm/web";
import { CommonOutput, ExpirationUnlockCondition, INodeInfoBaseToken, UnlockCondition, UnlockConditionType } from "@iota/sdk-wasm/web";
import moment from "moment/moment";

import { DateHelper } from "~helpers/dateHelper";
Expand All @@ -18,6 +18,7 @@ export interface ITransactionHistoryRecord {
balanceChange: number;
balanceChangeFormatted: string;
outputs: OutputWithDetails[];
isExpired: boolean;
}

export const groupOutputsByTransactionId = (outputsWithDetails: OutputWithDetails[]) => {
Expand Down Expand Up @@ -73,6 +74,8 @@ export const getTransactionHistoryRecords = (

const isSpent = balanceChange <= 0;

const isExpired = isTransactionExpired(outputs, balanceChange);

calculatedTransactions.push({
isGenesisByDate: isGenesisByDate,
isTransactionFromStardustGenesis: isTransactionFromStardustGenesis,
Expand All @@ -84,8 +87,10 @@ export const getTransactionHistoryRecords = (
balanceChange: balanceChange,
balanceChangeFormatted: (isSpent ? `-` : `+`) + formatAmount(Math.abs(balanceChange), tokenInfo, !isFormattedAmounts, 2, true),
outputs: outputs,
isExpired,
});
});

return calculatedTransactions;
};

Expand All @@ -111,3 +116,20 @@ export const getTransactionLink = (network: string, transactionId: string, isTra
? `/${CHRYSALIS_MAINNET}/search/${transactionId}`
: `/${network}/transaction/${transactionId}`;
};

function isExpirationUnlockCondition(unlockCondition: UnlockCondition): unlockCondition is ExpirationUnlockCondition {
return unlockCondition.type === UnlockConditionType.Expiration;
}

function isTransactionExpired(outputs: OutputWithDetails[], balanceChange: number): boolean {
const hasExpiredOutput = outputs.some((output) => {
const outputFromDetails = output?.details?.output as CommonOutput;

const expirationUnlockCondition = outputFromDetails.unlockConditions.find(isExpirationUnlockCondition);
const hasTimeExpired = expirationUnlockCondition && expirationUnlockCondition.unixTime < Date.now();

return hasTimeExpired;
});

return hasExpiredOutput && balanceChange <= 0;
}
Loading