Skip to content

Commit

Permalink
feat(suite): disable tx bumpfee except lowestnonc
Browse files Browse the repository at this point in the history
  • Loading branch information
enjojoy committed Sep 19, 2024
1 parent 6b43b7b commit 8d57659
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { memo, useMemo, useState } from 'react';
import styled, { css } from 'styled-components';
import { AnimatePresence } from 'framer-motion';
import { selectIsPhishingTransaction } from '@suite-common/wallet-core';
import { variables, Button, Card } from '@trezor/components';
import { variables, Button, Card, Link } from '@trezor/components';
import { Translation } from 'src/components/suite';
import { useDispatch, useSelector } from 'src/hooks/suite';
import { openModal } from 'src/actions/suite/modalActions';
Expand Down Expand Up @@ -35,6 +35,8 @@ import { BlurWrapper } from './TransactionItemBlurWrapper';
import { selectSelectedAccount } from 'src/reducers/wallet/selectedAccountReducer';
import { getInstantStakeType } from 'src/utils/suite/stake';
import { isStakeTypeTx } from '@suite-common/suite-utils';
import { Tooltip } from '@trezor/components';
import { HELP_CENTER_REPLACE_BY_FEE } from '@trezor/urls';

// eslint-disable-next-line local-rules/no-override-ds-component
const Wrapper = styled(Card)<{
Expand Down Expand Up @@ -88,6 +90,7 @@ interface TransactionItemProps {
network: Network;
accountType: AccountType;
className?: string;
disableBumpFee?: boolean;
index: number;
}

Expand All @@ -101,6 +104,7 @@ export const TransactionItem = memo(
network,
accountType,
className,
disableBumpFee,
index,
}: TransactionItemProps) => {
const [limit, setLimit] = useState(0);
Expand Down Expand Up @@ -183,6 +187,42 @@ export const TransactionItem = memo(
transaction.deadline ? '/prepending' : ''
}`;

const BumpFeeButton = ({ isDisabled }: { isDisabled: boolean }) => (
<Button
variant="tertiary"
onClick={() => openTxDetailsModal(true)}
isDisabled={isDisabled}
>
<Translation id="TR_BUMP_FEE" />
</Button>
);

const DisabledBumpFeeButtonWithTooltip = () => (
<Tooltip
content={
<div>
<Translation
id="TR_BUMP_FEE_DISABLED_TOOLTIP"
values={{
a: chunks => (
<Link
href={HELP_CENTER_REPLACE_BY_FEE}
variant="nostyle"
icon="externalLink"
type="hint"
>
{chunks}
</Link>
),
}}
/>
</div>
}
>
<BumpFeeButton isDisabled={true} />
</Tooltip>
);

// we are using slightly different layout for 1 targets txs to better match the design
// the only difference is that crypto amount is in the same row as tx heading/description
// fiat amount is in the second row along with address
Expand Down Expand Up @@ -418,12 +458,11 @@ export const TransactionItem = memo(
networkFeatures?.includes('rbf') &&
!transaction?.deadline && (
<NextRow>
<Button
variant="tertiary"
onClick={() => openTxDetailsModal(true)}
>
<Translation id="TR_BUMP_FEE" />
</Button>
{disableBumpFee ? (
<DisabledBumpFeeButtonWithTooltip />
) : (
<BumpFeeButton isDisabled={false} />
)}
</NextRow>
)}
</Content>
Expand Down
5 changes: 5 additions & 0 deletions packages/suite/src/support/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9157,4 +9157,9 @@ export default defineMessages({
defaultMessage:
'Setting a low fee might cause your transaction to fail or experience significant delays.',
},
TR_BUMP_FEE_DISABLED_TOOLTIP: {
id: 'TR_BUMP_FEE_DISABLED_TOOLTIP',
defaultMessage:
'To speed up your transactions, increase the fee on the first pending transaction in the queue (the one processed first). Transactions must be confirmed in order. <a>Learn more</a>',
},
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { GroupedTransactionsByDate, groupJointTransactions } from '@suite-common/wallet-utils';
import {
getTransactionWithLowestNonce,
GroupedTransactionsByDate,
groupJointTransactions,
} from '@suite-common/wallet-utils';
import { getNetwork } from '@suite-common/wallet-config';
import { CoinjoinBatchItem } from 'src/components/wallet/TransactionItem/CoinjoinBatchItem';
import { useSelector } from 'src/hooks/suite';
Expand All @@ -25,6 +29,9 @@ export const TransactionGroupedList = ({
const accountMetadata = useSelector(state => selectLabelingDataForAccount(state, account.key));
const network = getNetwork(symbol);

const transactionWithLowestNonce: WalletAccountTransaction | null =
getTransactionWithLowestNonce(transactionGroups);

return Object.entries(transactionGroups).map(([dateKey, value], groupIndex) => (
<TransactionsGroup
key={dateKey}
Expand Down Expand Up @@ -53,6 +60,11 @@ export const TransactionGroupedList = ({
network={network}
accountType={account.accountType}
index={index}
disableBumpFee={
network.networkType === 'ethereum'
? item.tx.txid !== transactionWithLowestNonce?.txid
: false
}
/>
),
)}
Expand Down
2 changes: 2 additions & 0 deletions packages/urls/src/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ export const HELP_CENTER_EVM_ADDRESS_CHECKSUM: Url =
'https://trezor.io/learn/a/evm-address-checksum-in-trezor-suite';
export const HELP_CENTER_FIRMWARE_REVISION_CHECK: Url =
'https://trezor.io/learn/a/trezor-firmware-revision-check';
export const HELP_CENTER_REPLACE_BY_FEE: Url =
'https://trezor.io/learn/a/replace-by-fee-rbf-ethereum';

export const INVITY_URL: Url = 'https://invity.io/';
export const INVITY_SCHEDULE_OF_FEES: Url = 'https://blog.invity.io/schedule-of-fees';
Expand Down
18 changes: 18 additions & 0 deletions suite-common/wallet-utils/src/transactionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1034,3 +1034,21 @@ export const groupTokensTransactionsByContractAddress = (

return groupedTokensTxs;
};

export const getTransactionWithLowestNonce = (
transactionGroups: GroupedTransactionsByDate,
): WalletAccountTransaction | null =>
Object.values(transactionGroups)
.flat()
.reduce<WalletAccountTransaction | null>((lowestNonceTransaction, transaction) => {
if (!transaction.ethereumSpecific) return null;
const currentNonce = Number(transaction.ethereumSpecific?.nonce);
if (
lowestNonceTransaction === null ||
currentNonce < Number(lowestNonceTransaction.ethereumSpecific?.nonce)
) {
lowestNonceTransaction = transaction;
}

return lowestNonceTransaction;
}, null);

0 comments on commit 8d57659

Please sign in to comment.