Skip to content
Open
Show file tree
Hide file tree
Changes from 11 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
16 changes: 12 additions & 4 deletions suite-common/wallet-core/src/fees/feesReducer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createReducer } from '@reduxjs/toolkit';

import { createWeakMapSelector } from '@suite-common/redux-utils';
import { formatDuration } from '@suite-common/suite-utils';
import { formatDurationStrict } from '@suite-common/suite-utils';
import { NetworkSymbol, getNetworkType } from '@suite-common/wallet-config';
import { FeeInfo, FeeLevelLabel, FeesState, FeesStatus } from '@suite-common/wallet-types';
import { getConvertedOrDefaultFeeInfo } from '@suite-common/wallet-utils';
Expand Down Expand Up @@ -96,11 +96,19 @@ export const selectNetworkFeeLevel = createMemoizedSelector(
);

export const selectConvertedNetworkFeeLevelTimeEstimate = createMemoizedSelector(
[selectConvertedNetworkFeeInfo, selectNetworkFeeLevel],
(networkFeeInfo, feeLevel): string | null => {
[
selectConvertedNetworkFeeInfo,
selectNetworkFeeLevel,
(_state: FeesRootState, symbol?: NetworkSymbol) => symbol,
],
(networkFeeInfo, feeLevel, symbol): string | null => {
if (!feeLevel || !networkFeeInfo) return null;

return formatDuration(networkFeeInfo.blockTime * feeLevel.blocks * 60);
const networkType = symbol ? getNetworkType(symbol) : null;

const multiplier = networkType === 'bitcoin' ? 60 : 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please explain multiplier by a comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh not sure why, could you help me to write the reason? I've seen the logic used here fc719ab. only I know is that thanks to that the duration is displayed correctly

Copy link
Contributor Author

@BrantalikP BrantalikP Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here thank you

return `~${formatDurationStrict(feeInfo.blockTime * fee.blocks * 60, locale)}`;


return formatDurationStrict(networkFeeInfo.blockTime * feeLevel.blocks * multiplier);
},
);

Expand Down
5 changes: 1 addition & 4 deletions suite-common/wallet-core/src/fees/feesUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Network, NetworkSymbol, getNetwork } from '@suite-common/wallet-config'
import { isEip1559 } from '@suite-common/wallet-utils';
import TrezorConnect, { FeeLevel } from '@trezor/connect';
import { BlockchainEstimatedFeeLevel } from '@trezor/connect/src/types/api/blockchainEstimateFee';
import { isNative } from '@trezor/env-utils';
import { BigNumber } from '@trezor/utils';

const NETWORK_FEE_OVERRIDES: Record<
Expand Down Expand Up @@ -35,9 +34,7 @@ type GetEip1559AvailabilityProps = {
export const getEip1559Availability = ({ symbol, feeLevel, device }: GetEip1559AvailabilityProps) =>
getNetwork(symbol).features.includes('eip1559') &&
isEip1559(feeLevel) &&
!device?.unavailableCapabilities?.['eip1559'] &&
// suite-native does not have eip1559 implementation yet #16372
!isNative();
!device?.unavailableCapabilities?.['eip1559'];

type GetNewFeeInfoProps = { network: Network; device?: TrezorDevice };
export const getNewFeeInfo = async ({
Expand Down
15 changes: 14 additions & 1 deletion suite-native/atoms/src/Sheet/BottomSheetModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
BottomSheetBackdrop,
BottomSheetBackdropProps,
BottomSheetModal as BottomSheetModalBase,
BottomSheetModalProps as BottomSheetModalBaseProps,
} from '@gorhom/bottom-sheet';
import { BottomSheetModalMethods } from '@gorhom/bottom-sheet/lib/typescript/types';

Expand All @@ -25,6 +26,7 @@ export type BottomSheetModalProps = {
subtitle?: ReactNode;
isCloseDisplayed?: boolean;
onDismiss?: () => void;
bottomSheetCustomProps?: Partial<BottomSheetModalBaseProps>;
} & BoxProps;

const backgroundStyle = prepareNativeStyle(utils => ({
Expand All @@ -35,7 +37,17 @@ export type BottomSheetModalRef = Ref<BottomSheetModalMethods>;

export const BottomSheetModal = forwardRef<BottomSheetModalMethods, BottomSheetModalProps>(
(
{ children, footer, style, title, isCloseDisplayed = false, subtitle, onDismiss, ...rest },
{
children,
footer,
style,
title,
isCloseDisplayed = false,
subtitle,
onDismiss,
bottomSheetCustomProps = {},
...rest
},
ref,
) => {
const { applyStyle } = useNativeStyles();
Expand Down Expand Up @@ -74,6 +86,7 @@ export const BottomSheetModal = forwardRef<BottomSheetModalMethods, BottomSheetM
/>
)}
onDismiss={onDismiss}
{...bottomSheetCustomProps}
>
<BottomSheetModalContent handleScroll={handleScroll} style={style} {...rest}>
{children}
Expand Down
1 change: 1 addition & 0 deletions suite-native/atoms/src/Sheet/BottomSheetModalContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const BottomSheetModalContent = memo<BottomSheetModalContentProps>(
onScroll={handleScroll}
testID="@bottom-sheet/scroll-view"
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={false}
>
<AnimatedBox
style={[applyStyle(childWrapperStyle, { bottomInset: bottom }), style]}
Expand Down
21 changes: 20 additions & 1 deletion suite-native/intl/src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2772,12 +2772,13 @@ export const messages = {
high: 'High',
},
description: {
title: 'Transaction fee',
title: { general: 'Transaction fee', ethereum: 'Maximum fee' },
body: 'Fees are paid directly to validators for processing your transactions.',
},
custom: {
addButton: 'Add custom fee',
bottomSheet: {
currentBaseFeeEthereum: 'Current base fee: {baseFee}',
title: 'Custom fee',
minimumLabel: 'The minimum fee rate is {feePerUnit}',
label: {
Expand All @@ -2787,6 +2788,24 @@ export const messages = {
maxFeePerGas: 'Max fee per gas',
maxPriorityFeePerGas: 'Max priority fee per gas',
},
errors: {
feeLimit: {
low: 'Value is too low.',
},
decimals: 'Too many decimals.',
feePerUnit: {
low: 'Fee is too low.',
high: 'Fee is too high.',
},
maxFeePerGas: {
lessThanPriority: 'This fee can’t be lower than Max priority fee.',
outOfRange: 'Enter a max fee per gas between {minFee} and {maxFee}',
},
maxPriorityFee: {
min: 'Max priority fee must be at least {minPriorityFee}',
higherThanMaxFee: 'This fee can’t be higher than Max fee per gas',
},
},
total: 'Total fee',
confirmButton: 'Confirm custom fee',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,20 @@ export const CorrectNetworkMessageCard = ({ symbol }: CorrectNetworkMessageCardP
id="moduleSend.outputs.correctNetworkMessage"
values={{
networkName,
link: linkChunk => (
<Link
href={HOW_TO_CHOOSE_RIGHT_NETWORK_URL}
label={linkChunk}
isUnderlined
textVariant="hint"
textColor="textDefault"
/>
),
link: linkChunk => {
const label = (linkChunk[0] as string) ?? '';

return (
<Link
key={label}
href={HOW_TO_CHOOSE_RIGHT_NETWORK_URL}
label={label}
isUnderlined
textVariant="hint"
textColor="textDefault"
/>
);
},
}}
/>
</Text>
Expand Down
6 changes: 3 additions & 3 deletions suite-native/module-send/src/components/SendFeesForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
import { useNavigation } from '@react-navigation/native';

import { SendRootState, selectSendFormDraftByKey } from '@suite-common/wallet-core';
import { AccountKey, TokenAddress } from '@suite-common/wallet-types';
import { AccountKey, FeeLevelLabel, TokenAddress } from '@suite-common/wallet-types';
import { VStack } from '@suite-native/atoms';
import { Form } from '@suite-native/forms';
import {
Expand All @@ -21,7 +21,6 @@ import {
FeesContent,
FeesFooter,
NativeSendRootState,
NativeSupportedFeeLevel,
useFeesManagement,
} from '@suite-native/transaction-management';

Expand Down Expand Up @@ -69,7 +68,7 @@ export const SendFeesForm = ({ accountKey, tokenContract }: SendFormProps) => {
accountKey,
tokenContract,
updateThunk: updateSelectedFeeLevelThunk,
selectedFee: formDraft?.selectedFee as NativeSupportedFeeLevel,
selectedFee: formDraft?.selectedFee as FeeLevelLabel,
selectedFeePerUnit: formDraft?.feePerUnit,
selectedSetMaxOutputId: formDraft?.setMaxOutputId,
});
Expand Down Expand Up @@ -148,6 +147,7 @@ export const SendFeesForm = ({ accountKey, tokenContract }: SendFormProps) => {
selectedFeeLevel={selectedFeeLevel}
feeLevels={feeLevels}
symbol={symbol}
networkType={account.networkType}
accountKey={accountKey}
areFeesLoading={areFeesLoading}
onSelectedFeeLevel={handleFeeLevelChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
import { RouteProp, useRoute } from '@react-navigation/native';

import { FormDraftRootState, selectDeepCopyOfFormDraft } from '@suite-common/wallet-core';
import { AccountKey, FormDraftKeyPrefix, TokenAddress } from '@suite-common/wallet-types';
import {
AccountKey,
FeeLevelLabel,
FormDraftKeyPrefix,
TokenAddress,
} from '@suite-common/wallet-types';
import { getFormDraftKey } from '@suite-common/wallet-utils';
import { VStack } from '@suite-native/atoms';
import { Form } from '@suite-native/forms';
import { TradingStackParamList, TradingStackRoutes } from '@suite-native/navigation';
import {
FeesContent,
FeesFooter,
NativeSupportedFeeLevel,
useFeesManagement,
} from '@suite-native/transaction-management';
import { FeesContent, FeesFooter, useFeesManagement } from '@suite-native/transaction-management';

import { updateTradingSelectedFeeLevelThunk } from '../../thunks';

Expand Down Expand Up @@ -51,7 +51,7 @@ export const TradingFeesForm = ({ accountKey, tokenContract }: TradingFeesFormPr
accountKey,
tokenContract,
updateThunk: updateTradingSelectedFeeLevelThunk,
selectedFee: formDraft?.selectedFee as NativeSupportedFeeLevel,
selectedFee: formDraft?.selectedFee as FeeLevelLabel,
selectedFeePerUnit: formDraft?.feePerUnit,
selectedSetMaxOutputId: formDraft?.setMaxOutputId,
formDraftKey,
Expand All @@ -73,6 +73,7 @@ export const TradingFeesForm = ({ accountKey, tokenContract }: TradingFeesFormPr
onSelectedFeeLevel={handleFeeLevelChange}
onCustomFeeSet={handleCustomFeeSet}
formDraft={formDraft}
networkType={account.networkType}
/>
{!!totalAmount && !!fee && (
<FeesFooter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,10 @@ import {
selectSendSerializedTx,
updateFeeInfoThunk,
} from '@suite-common/wallet-core';
import { TokenAddress } from '@suite-common/wallet-types';
import { FeeLevelLabel, TokenAddress } from '@suite-common/wallet-types';
import { TokensRootState, selectAccountTokenDecimals } from '@suite-native/tokens';
import { TradingRootState, getFormDraftKeyByTradeType } from '@suite-native/trading-state';
import {
NativeSupportedFeeLevel,
selectFeeLevels,
useFeesFetching,
usePrecomposedTransactionError,
Expand All @@ -50,9 +49,11 @@ export type TradingTransactionSignAndSendProps = {
};

export type TradingTransactionComposeProps = {
selectedFeeLevel?: NativeSupportedFeeLevel;
selectedFeeLevel?: FeeLevelLabel;
feePerUnit?: string;
feeLimit?: string;
maxFeePerGas?: string;
maxPriorityFeePerGas?: string;
};

export type UseTradingTransactionProps = {
Expand Down Expand Up @@ -105,7 +106,13 @@ export const useTradingTransaction = ({
selectDeepCopyOfFormDraft(state, getFormDraftKeyByTradeType(tradeType)),
);

const { selectedFee, feePerUnit: feePerUnitDraft, feeLimit: feeLimitDraft } = draft ?? {};
const {
selectedFee,
feePerUnit: feePerUnitDraft,
feeLimit: feeLimitDraft,
maxFeePerGas: maxFeePerGasDraft,
maxPriorityFeePerGas: maxPriorityFeePerGasDraft,
} = draft ?? {};

const { contractAddress } = cryptoIdToNetworkAndContractAddress(
tradeType === 'exchange'
Expand All @@ -129,7 +136,7 @@ export const useTradingTransaction = ({

const feeLevels = useSelector(selectFeeLevels);

const selectedLevel = feeLevels[(selectedFee as NativeSupportedFeeLevel) ?? 'normal'];
const selectedLevel = feeLevels[(selectedFee as FeeLevelLabel) ?? 'normal'];
const feeError = selectedLevel?.type === 'error' ? selectedLevel.error : null;

const txnErrorString = usePrecomposedTransactionError({
Expand All @@ -156,7 +163,13 @@ export const useTradingTransaction = ({

// this is called when we want to compose a transaction
const composeRequest = useCallback(
async ({ selectedFeeLevel, feePerUnit, feeLimit }: TradingTransactionComposeProps) => {
async ({
selectedFeeLevel,
feePerUnit,
feeLimit,
maxPriorityFeePerGas,
maxFeePerGas,
}: TradingTransactionComposeProps) => {
if (!sendAccount || !networkFeeInfo) {
console.error(
'Send account and networkFeeInfo are required for composing transaction',
Expand All @@ -175,6 +188,8 @@ export const useTradingTransaction = ({
selectedFeeLevel,
feePerUnit,
feeLimit,
maxPriorityFeePerGas,
maxFeePerGas,
}),
).unwrap();

Expand Down Expand Up @@ -202,11 +217,22 @@ export const useTradingTransaction = ({
}

await composeRequest({
selectedFeeLevel: selectedFee as NativeSupportedFeeLevel,
selectedFeeLevel: selectedFee as FeeLevelLabel,
feePerUnit: feePerUnitDraft,
feeLimit: feeLimitDraft,
maxFeePerGas: maxFeePerGasDraft,
maxPriorityFeePerGas: maxPriorityFeePerGasDraft,
});
}, [dispatch, sendAccount, composeRequest, selectedFee, feePerUnitDraft, feeLimitDraft]);
}, [
sendAccount,
dispatch,
composeRequest,
selectedFee,
feePerUnitDraft,
feeLimitDraft,
maxFeePerGasDraft,
maxPriorityFeePerGasDraft,
]);

// this is the reusable signAndPushSendFormTransaction function
// waitForPushApproval is used so that we can wait for the user to approve the transaction before sending it
Expand Down Expand Up @@ -311,9 +337,11 @@ export const useTradingTransaction = ({
useEffect(() => {
if (selectedFee && networkFeeInfo) {
composeRequest({
selectedFeeLevel: selectedFee as NativeSupportedFeeLevel,
selectedFeeLevel: selectedFee as FeeLevelLabel,
feePerUnit: feePerUnitDraft,
feeLimit: feeLimitDraft,
maxFeePerGas: maxFeePerGasDraft,
maxPriorityFeePerGas: maxPriorityFeePerGasDraft,
});
}
}, [
Expand All @@ -323,6 +351,8 @@ export const useTradingTransaction = ({
feeLimitDraft,
networkFeeInfo,
selectedQuote,
maxFeePerGasDraft,
maxPriorityFeePerGasDraft,
]);

return {
Expand Down
Loading
Loading