Skip to content

Commit

Permalink
chore(suite): wip
Browse files Browse the repository at this point in the history
  • Loading branch information
enjojoy committed Mar 1, 2025
1 parent 0c8da1f commit aad7d97
Show file tree
Hide file tree
Showing 17 changed files with 262 additions and 82 deletions.
20 changes: 1 addition & 19 deletions packages/connect/src/api/ethereum/EthereumFees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BigNumber } from '@trezor/utils/src/bigNumber';

import { Blockchain } from '../../backend/BlockchainLink';
import type { EthereumNetworkInfo, FeeLevel } from '../../types';
import { Blocks, MiscFeeLevels, findBlocksForFee } from '../common/MiscFees';
import { Blocks, MiscFeeLevels } from '../common/MiscFees';

type EipResponse1559Level = 'low' | 'medium' | 'high';
type Eip1559Level = 'low' | 'normal' | 'high';
Expand Down Expand Up @@ -72,22 +72,4 @@ export class EthereumFeeLevels extends MiscFeeLevels {

return this.levels;
}

updateEthereumCustomFee(
feePerUnit: string,
effectiveGasPrice?: string,
maxPriorityFeePerGas?: string,
) {
// remove "custom" level from list
this.levels = this.levels.filter(l => l.label !== 'custom');
// recreate "custom" level
const blocks = findBlocksForFee(feePerUnit, this.blocks);
this.levels.push({
label: 'custom',
feePerUnit,
blocks,
maxPriorityFeePerGas,
effectiveGasPrice,
});
}
}
10 changes: 2 additions & 8 deletions packages/connect/src/types/fees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,6 @@ export const FeeInfo = Type.Object({
dustLimit: Type.Number(),
});

export type PriorityFeeEstimationDetails = Static<typeof PriorityFeeEstimationDetails>;
export const PriorityFeeEstimationDetails = Type.Object({
maxFeePerGas: Type.String(),
maxPriorityFeePerGas: Type.String(),
maxWaitTimeEstimate: Type.Optional(Type.Number()),
minWaitTimeEstimate: Type.Optional(Type.Number()),
});

export type FeeLevel = Static<typeof FeeLevel>;
export const FeeLevel = Type.Object({
label: Type.Union([
Expand All @@ -32,6 +24,8 @@ export const FeeLevel = Type.Object({
baseFeePerGas: Type.Optional(Type.String()),
maxFeePerGas: Type.Optional(Type.String()),
effectiveGasPrice: Type.Optional(Type.String()),
customMaxBaseFeePerGas: Type.Optional(Type.String()),
customMaxPriorityFeePerGas: Type.Optional(Type.String()),
maxPriorityFeePerGas: Type.Optional(Type.String()),
maxWaitTimeEstimate: Type.Optional(Type.Number()),
minWaitTimeEstimate: Type.Optional(Type.Number()),
Expand Down
5 changes: 5 additions & 0 deletions packages/suite/src/actions/wallet/stake/stakeFormActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ export const calculate = (
max,
fee: feeInBaseUnits,
feePerByte: feeLevel.feePerUnit,
maxFeePerGas: feeLevel.effectiveGasPrice || undefined,
maxPriorityFeePerGas: feeLevel.maxPriorityFeePerGas || undefined,
feeLimit: feeLevel.feeLimit,
bytes: 0,
inputs: [],
Expand Down Expand Up @@ -123,6 +125,7 @@ export const composeStakingTransaction = (
) => {
const { account, network } = formState;
const composeOutputs = getExternalComposeOutput(formValues, account, network);
console.log('composeOutputs', formValues, composeOutputs);
if (!composeOutputs) return; // no valid Output

const { output, decimals } = composeOutputs;
Expand All @@ -131,6 +134,8 @@ export const composeStakingTransaction = (
// wrap response into PrecomposedLevels object where key is a FeeLevel label
const wrappedResponse: PrecomposedLevels = {};
const compareWithAmount = formValues.stakeType === 'stake';

console.log('predefinedLevels', predefinedLevels);
const response = predefinedLevels.map(level =>
calculateTransaction(
availableBalance,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import {
UNSTAKE_INTERCHANGES,
} from '@suite-common/wallet-constants';
import { ComposeActionContext, selectSelectedDevice } from '@suite-common/wallet-core';
import { calculateEffectiveGasPrice } from '@suite-common/wallet-core/src/send/sendFormEthereumUtils';
import {
AddressDisplayOptions,
ExternalOutput,
PrecomposedTransaction,
PrecomposedTransactionFinal,
StakeFormState,
} from '@suite-common/wallet-types';
import { calculateEthFee, getAccountIdentity, isPending } from '@suite-common/wallet-utils';
import { calculateMaxEthFee, getAccountIdentity, isPending } from '@suite-common/wallet-utils';
import TrezorConnect, { FeeLevel } from '@trezor/connect';
import { BigNumber } from '@trezor/utils/src/bigNumber';

Expand All @@ -31,14 +32,18 @@ import {

import { calculate, composeStakingTransaction } from './stakeFormActions';

const calculateTransaction = (
const calculateStakingTransaction = (
availableBalance: string,
output: ExternalOutput,
feeLevel: FeeLevel,
compareWithAmount = true,
symbol: NetworkSymbol,
): PrecomposedTransaction => {
const feeInWei = calculateEthFee(toWei(feeLevel.feePerUnit, 'gwei'), feeLevel.feeLimit || '0');
const isEip1559 = feeLevel.maxPriorityFeePerGas !== undefined;

const feeInWei = isEip1559
? calculateMaxEthFee(feeLevel.effectiveGasPrice, feeLevel.feeLimit)
: calculateMaxEthFee(toWei(feeLevel.feePerUnit, 'gwei'), feeLevel.feeLimit);

const stakingParams = {
feeInBaseUnits: feeInWei,
Expand All @@ -47,6 +52,8 @@ const calculateTransaction = (
minAmountForWithdrawalInBaseUnits: toWei(MIN_ETH_FOR_WITHDRAWALS.toString(), 'ether'),
};

console.log('feeLevel', feeLevel);

return calculate(availableBalance, output, feeLevel, compareWithAmount, symbol, stakingParams);
};

Expand Down Expand Up @@ -81,11 +88,20 @@ export const composeTransaction =
predefinedLevels.forEach(l => (l.feeLimit = customFeeLimit));
}
// in case when selectedFee is set to 'custom' construct this FeeLevel from values
//TODO: calculate effective gas price here?
if (formValues.selectedFee === 'custom') {
const calculatedEffectiveGasPrice = calculateEffectiveGasPrice(
formValues.customMaxPriorityFeePerGas,
formValues.customMaxBaseFeePerGas,
);
predefinedLevels.push({
label: 'custom',
feePerUnit: formValues.feePerUnit,
feeLimit: formValues.feeLimit,
customMaxBaseFeePerGas: formValues.customMaxBaseFeePerGas,
customMaxPriorityFeePerGas: formValues.customMaxPriorityFeePerGas,
effectiveGasPrice: calculatedEffectiveGasPrice,
maxPriorityFeePerGas: toWei(Number(formValues.customMaxPriorityFeePerGas), 'gwei'),
blocks: -1,
});
}
Expand All @@ -94,7 +110,7 @@ export const composeTransaction =
formValues,
formState,
predefinedLevels,
calculateTransaction,
calculateStakingTransaction,
undefined,
customFeeLimit,
);
Expand Down Expand Up @@ -150,6 +166,8 @@ export const signTransaction =
identity,
amount: formValues.outputs[0].amount,
gasPrice: transactionInfo.feePerByte,
maxFeePerGas: transactionInfo.maxFeePerGas,
maxPriorityFeePerGas: transactionInfo.maxPriorityFeePerGas,
nonce,
chainId: network.chainId,
});
Expand All @@ -161,6 +179,8 @@ export const signTransaction =
identity,
amount: formValues.outputs[0].amount,
gasPrice: transactionInfo.feePerByte,
maxFeePerGas: transactionInfo.maxFeePerGas,
maxPriorityFeePerGas: transactionInfo.maxPriorityFeePerGas,
nonce,
chainId: network.chainId,
interchanges: UNSTAKE_INTERCHANGES,
Expand All @@ -172,6 +192,8 @@ export const signTransaction =
from: account.descriptor,
identity,
gasPrice: transactionInfo.feePerByte,
maxFeePerGas: transactionInfo.maxFeePerGas,
maxPriorityFeePerGas: transactionInfo.maxPriorityFeePerGas,
nonce,
chainId: network.chainId,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { formatDurationStrict } from '@suite-common/suite-utils';
import { NetworkType, networks } from '@suite-common/wallet-config';
import { NetworkType, getNetworkFeatures, networks } from '@suite-common/wallet-config';
import { FeeInfo, GeneralPrecomposedTransactionFinal, StakeType } from '@suite-common/wallet-types';
import { getFee } from '@suite-common/wallet-utils';
import { Box, IconButton, Note, Row, Text } from '@trezor/components';
Expand Down Expand Up @@ -47,14 +47,22 @@ export const TransactionReviewSummary = ({
const fees = useSelector(state => state.wallet.fees);
const locale = useLocales();
const { symbol, accountType, index, networkType } = account;

const network = networks[symbol];
const fee = getFee(networkType, tx);

const baseFee = fees[symbol].levels[0].baseFeePerGas;
const hasEip1559Feature = getNetworkFeatures(symbol).includes('eip1559');
const shouldUsePriorityFees = !!tx.fee && hasEip1559Feature && !!baseFee;
const fee = getFee({ account, tx, shouldUsePriorityFees });

const estimateTime = getEstimatedTime(networkType, fees[account.symbol], tx);

const formFeeRate = drafts[currentAccountKey]?.feePerUnit;
const isFeeCustom = drafts[currentAccountKey]?.selectedFee === 'custom';
const isComposedFeeRateDifferent = isFeeCustom && formFeeRate !== fee;

const isEthereumNetworkType = networkType === 'ethereum';

return (
<Row columnGap={spacings.md} rowGap={spacings.xxs} flexWrap="wrap">
<Row gap={spacings.xxs}>
Expand All @@ -74,25 +82,23 @@ export const TransactionReviewSummary = ({
</Note>
)}

{!!tx.feeLimit && network.networkType !== 'solana' && (
{!!tx.feeLimit && network.networkType !== 'solana' && !hasEip1559Feature && (
<Note iconName="gasPump">
<Translation id="TR_GAS_LIMIT" />
{': '}
{tx.feeLimit}
</Note>
)}

{networkType === 'ethereum' ? (
<Note iconName="gasPump">
<Translation id="TR_GAS_PRICE" />
{': '}
<FeeRate feeRate={fee} networkType={network.networkType} symbol={symbol} />
</Note>
) : (
<Note iconName="receipt">
<FeeRate feeRate={fee} networkType={network.networkType} symbol={symbol} />
</Note>
)}
<Note iconName={isEthereumNetworkType ? 'gasPump' : 'receipt'}>
{isEthereumNetworkType && (
<>
<Translation id="TR_GAS_PRICE" />
{': '}
</>
)}
<FeeRate feeRate={fee} networkType={network.networkType} symbol={symbol} />
</Note>

{isComposedFeeRateDifferent && network.networkType === 'bitcoin' && (
<Translation id="TR_FEE_RATE_CHANGED" />
Expand Down
5 changes: 4 additions & 1 deletion packages/suite/src/hooks/wallet/form/useStakeCompose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,12 @@ export const useStakeCompose = <TFieldValues extends StakeFormState>({
setValue('selectedFee', nearest);
if (nearest === 'custom') {
// @ts-expect-error: type = error already filtered above
const { feePerByte, feeLimit } = composed;
const { feePerByte, feeLimit, effectiveGasPrice, maxPriorityFeePerGas } =
composed;
setValue('feePerUnit', feePerByte);
setValue('feeLimit', feeLimit || '');
setValue('customMaxPriorityFeePerGas', maxPriorityFeePerGas || '');
setValue('customMaxBaseFeePerGas', effectiveGasPrice || '');
}
}
// or do nothing, use default composed tx
Expand Down
7 changes: 7 additions & 0 deletions packages/suite/src/hooks/wallet/useTradingRecomposeAndSign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ export const useTradingRecomposeAndSign = () => {
setMaxOutputId: !composed.token?.contract ? setMaxOutputId : undefined,
selectedFee,
feePerUnit: composed.feePerByte,
maxFeePerGas: composed.maxFeePerGas,
maxPriorityFeePerGas: composed.maxPriorityFeePerGas,
customMaxBaseFeePerGas: composed.maxFeePerGas,
customMaxPriorityFeePerGas: composed.maxPriorityFeePerGas,
feeLimit: composed.feeLimit || '',
estimatedFeeLimit: composed.estimatedFeeLimit,
options,
Expand All @@ -85,6 +89,8 @@ export const useTradingRecomposeAndSign = () => {
networkType: account.networkType,
feeInfo: fees[account.symbol],
});

console.log('feeInfo', feeInfo, formState);
const composeContext = { account, network, feeInfo };

// recalcCustomLimit is used in case of custom fee level, when we want to keep the feePerUnit defined by the user
Expand Down Expand Up @@ -124,6 +130,7 @@ export const useTradingRecomposeAndSign = () => {

return;
}
//TODO priority
formState.feeLimit = normalLevels.normal.feeLimit;
}

Expand Down
9 changes: 8 additions & 1 deletion packages/suite/src/reducers/wallet/tradingReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,14 @@ import { Action } from 'src/types/suite';
export interface ComposedTransactionInfo {
composed?: Pick<
PrecomposedTransactionFinal,
'feePerByte' | 'estimatedFeeLimit' | 'feeLimit' | 'token' | 'fee'
| 'feePerByte'
| 'estimatedFeeLimit'
| 'feeLimit'
| 'token'
| 'fee'
| 'maxFeePerGas'
| 'maxPriorityFeePerGas'
| 'effectiveGasPrice'
>;
selectedFee?: FeeLevel['label'];
}
Expand Down
32 changes: 32 additions & 0 deletions packages/suite/src/support/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3440,6 +3440,18 @@ export default defineMessages({
id: 'TR_CURRENT_FEE_CUSTOM_FEES',
defaultMessage: 'Current network fee:',
},
TR_CURRENT_BASE_FEE: {
id: 'TR_CURRENT_BASE_FEE',
defaultMessage: 'Current network base fee:',
},
TR_MAX_BASE_FEE_PER_GAS: {
id: 'TR_MAX_BASE_FEE_PER_GAS',
defaultMessage: 'Max base fee',
},
TR_CUSTOM_MAX_BASE_FEE_USE_NETWORK_BASE_FEE: {
id: 'TR_CUSTOM_MAX_BASE_FEE_USE_NETWORK_BASE_FEE',
defaultMessage: 'Use network base fee',
},
GAS_LIMIT_IS_NOT_SET: {
id: 'GAS_LIMIT_IS_NOT_SET',
defaultMessage: 'Set gas limit for this transaction',
Expand Down Expand Up @@ -5585,6 +5597,10 @@ export default defineMessages({
description: 'Label in Send form for Ethereum network type',
id: 'MAX_FEE',
},
WHY_FEES: {
defaultMessage: 'Why fees?',
id: 'WHY_FEES',
},
EXPECTED_FEE: {
defaultMessage: 'Expected fee',
description: 'Label in Send form for Solana network type',
Expand All @@ -5610,6 +5626,18 @@ export default defineMessages({
defaultMessage: 'Low',
id: 'FEE_LEVEL_LOW',
},
FEE_LEVEL_MEDIUM: {
defaultMessage: 'Medium',
id: 'FEE_LEVEL_MEDIUM',
},
TR_MAX_PRIORITY_FEE_PER_GAS: {
defaultMessage: 'Priority fee',
id: 'TR_MAX_PRIORITY_FEE_PER_GAS',
},
TR_MAX_FEE_PER_GAS: {
defaultMessage: 'Max fee',
id: 'TR_MAX_FEE_PER_GAS',
},
CUSTOM_FEE_IS_NOT_SET: {
defaultMessage:
'Enter the fee rate you want to spend in order to complete this transaction.',
Expand All @@ -5623,6 +5651,10 @@ export default defineMessages({
defaultMessage: 'Enter a fee between {minFee} and {maxFee}',
id: 'CUSTOM_FEE_NOT_IN_RANGE',
},
TR_CUSTOM_FEE_BASE_FEE_BELOW_CURRENT: {
defaultMessage: 'Custom base fee can not be below current network base fee.',
id: 'TR_CUSTOM_FEE_BASE_FEE_BELOW_CURRENT',
},
CUSTOM_FEE_LIMIT_BELOW_RECOMMENDED: {
defaultMessage: 'Gas limit too low',
id: 'CUSTOM_FEE_LIMIT_BELOW_RECOMMENDED',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ import {
describe('transformTx', () => {
transformTxFixtures.forEach(test => {
it(test.description, () => {
const result = transformTx(test.tx, test.gasPrice, test.nonce, test.chainId);
const result = transformTx({
tx: test.tx,
gasPrice: test.gasPrice,
nonce: test.nonce,
chainId: test.chainId,
});
expect(result).toEqual(test.result);
expect(result).not.toHaveProperty('from');
});
Expand Down
Loading

0 comments on commit aad7d97

Please sign in to comment.