Skip to content

Commit

Permalink
feat(suite): build priority fees levels
Browse files Browse the repository at this point in the history
  • Loading branch information
enjojoy committed Jan 17, 2025
1 parent f54f628 commit 5bfb927
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 20 deletions.
21 changes: 21 additions & 0 deletions packages/blockchain-link-types/src/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,33 @@ export interface GetFiatRatesTickersList {
};
}

export interface PriorityFeeEstimationDetails {
maxFeePerGas: string;
maxPriorityFeePerGas: string;
minWaitTimeEstimate: number;
maxWaitTimeEstimate: number;
}

export type FeeTrend = 'up' | 'down';

export interface EstimateFee {
type: typeof RESPONSES.ESTIMATE_FEE;
payload: {
feePerUnit: string;
feePerTx?: string;
feeLimit?: string;
eip1559?: {
baseFeePerGas: string;
low: PriorityFeeEstimationDetails;
medium: PriorityFeeEstimationDetails;
high: PriorityFeeEstimationDetails;
networkCongestion: number;
latestPriorityFeeRange: string[];
historicalPriorityFeeRange: string[];
historicalBaseFeeRange: string[];
priorityFeeTrend: FeeTrend;
baseFeeTrend: FeeTrend;
};
}[];
}

Expand Down
53 changes: 41 additions & 12 deletions packages/connect/src/api/bitcoin/Fees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,48 @@ export class FeeLevels {
async loadMisc(blockchain: Blockchain) {
try {
const [response] = await blockchain.estimateFee({ blocks: [1] });

if (response.eip1559) {
const eip1559LevelKeys = ['low', 'medium', 'high'] as const;

const { eip1559, ...baseLevel } = response;
const eip1559Levels = eip1559LevelKeys.map(levelKey => {
const level = eip1559[levelKey];

return {
label: levelKey,
baseFeePerGas: eip1559.baseFeePerGas,
maxFeePerGas: level.maxFeePerGas,
maxPriorityFeePerGas: level.maxPriorityFeePerGas,
minWaitTimeEstimate: level.minWaitTimeEstimate,
maxWaitTimeEstimate: level.maxWaitTimeEstimate,
feePerUnit: '0',
feeLimit: undefined,
ethFeeType: 'eip1559' as const,
blocks: -1,
};
});

this.levels = [
{ ...baseLevel, label: 'normal' as const, blocks: -1, ethFeeType: 'legacy' },
...eip1559Levels,
];
} else {
this.levels[0] = {
...this.levels[0],
...response,
// validate `feePerUnit` from the backend
// should be lower than `coinInfo.maxFee` and higher than `coinInfo.minFee`
// xrp sends values from 1 to very high number occasionally
// see: https://github.com/trezor/trezor-suite/blob/develop/packages/blockchain-link/src/workers/ripple/index.ts#L316
feePerUnit: Math.min(
this.coinInfo.maxFee,
Math.max(this.coinInfo.minFee, parseInt(response.feePerUnit, 10)),
).toString(),
};
}

// misc coins should have only one FeeLevel (normal)
this.levels[0] = {
...this.levels[0],
...response,
// validate `feePerUnit` from the backend
// should be lower than `coinInfo.maxFee` and higher than `coinInfo.minFee`
// xrp sends values from 1 to very high number occasionally
// see: https://github.com/trezor/trezor-suite/blob/develop/packages/blockchain-link/src/workers/ripple/index.ts#L316
feePerUnit: Math.min(
this.coinInfo.maxFee,
Math.max(this.coinInfo.minFee, parseInt(response.feePerUnit, 10)),
).toString(),
};
} catch {
// silent
}
Expand Down
15 changes: 15 additions & 0 deletions packages/connect/src/types/fees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ 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.Number(),
minWaitTimeEstimate: Type.Number(),
});

export type FeeLevel = Static<typeof FeeLevel>;
export const FeeLevel = Type.Object({
label: Type.Union([
Expand All @@ -16,11 +24,18 @@ export const FeeLevel = Type.Object({
Type.Literal('economy'),
Type.Literal('low'),
Type.Literal('custom'),
Type.Literal('medium'),
]),
ethFeeType: Type.Optional(Type.Union([Type.Literal('legacy'), Type.Literal('eip1559')])),
feePerUnit: Type.String(),
blocks: Type.Number(),
feeLimit: Type.Optional(Type.String()), // eth gas limit
feePerTx: Type.Optional(Type.String()), // fee for BlockchainEstimateFeeParams.request.specific
baseFeePerGas: Type.Optional(Type.String()),
maxFeePerGas: Type.Optional(Type.String()),
maxPriorityFeePerGas: Type.Optional(Type.String()),
maxWaitTimeEstimate: Type.Optional(Type.Number()),
minWaitTimeEstimate: Type.Optional(Type.Number()),
});

export type SelectFeeLevel = Static<typeof SelectFeeLevel>;
Expand Down
1 change: 1 addition & 0 deletions packages/suite/src/components/wallet/Fees/Fees.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const FEE_LEVELS_TRANSLATIONS: Record<FeeLevel['label'], TranslationKey> = {
normal: 'FEE_LEVEL_NORMAL',
economy: 'FEE_LEVEL_LOW',
low: 'FEE_LEVEL_LOW',
medium: 'FEE_LEVEL_MEDIUM',
} as const;

const buildFeeOptions = (levels: FeeLevel[]) =>
Expand Down
4 changes: 4 additions & 0 deletions packages/suite/src/support/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5592,6 +5592,10 @@ export default defineMessages({
defaultMessage: 'Low',
id: 'FEE_LEVEL_LOW',
},
FEE_LEVEL_MEDIUM: {
defaultMessage: 'Medium',
id: 'FEE_LEVEL_MEDIUM',
},
CUSTOM_FEE_IS_NOT_SET: {
defaultMessage:
'Enter the fee rate you want to spend in order to complete this transaction.',
Expand Down
8 changes: 3 additions & 5 deletions suite-common/wallet-core/src/blockchain/blockchainThunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const getAccountSyncInterval = (symbol: NetworkSymbol) =>

// sort FeeLevels in reversed order (Low > High)
// TODO: consider to use same order in @trezor/connect to avoid double sorting
const order: FeeLevel['label'][] = ['low', 'economy', 'normal', 'high'];
const order: FeeLevel['label'][] = ['low', 'economy', 'medium', 'normal', 'high'];
const sortLevels = (levels: FeeLevel[]) =>
levels.sort((levelA, levelB) => order.indexOf(levelA.label) - order.indexOf(levelB.label));

Expand Down Expand Up @@ -124,13 +124,11 @@ export const updateFeeInfoThunk = createThunk(
let newFeeInfo;

if (network.networkType === 'ethereum') {
// NOTE: ethereum smart fees are not implemented properly in @trezor/connect Issue: https://github.com/trezor/trezor-suite/issues/5340
// create raw call to @trezor/blockchain-link, receive data and create FeeLevel.normal from it

const result = await TrezorConnect.blockchainEstimateFee({
coin: network.symbol,
request: {
blocks: [2],
feeLevels: 'smart',
specific: {
from: '0x0000000000000000000000000000000000000000',
to: '0x0000000000000000000000000000000000000000',
Expand All @@ -143,7 +141,7 @@ export const updateFeeInfoThunk = createThunk(
levels: result.payload.levels.map(l => ({
...l,
blocks: -1, // NOTE: @trezor/connect returns -1 for ethereum default
label: 'normal' as const,
label: l.label || ('normal' as const),
})),
};
}
Expand Down
4 changes: 3 additions & 1 deletion suite-common/wallet-types/src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ export type EthTransactionData = {
amount: string;
data?: string;
gasLimit: string;
gasPrice: string;
nonce: string;
gasPrice?: string; // this field is not used for EIP1559 transactions (See EthereumTransaction and EthereumTransactionEIP1559 types in connect)
maxFeePerGas?: string;
maxPriorityFeePerGas?: string;
};

export type ExternalOutput = Exclude<ComposeOutput, { type: 'opreturn' } | { address_n: number[] }>;
Expand Down
2 changes: 1 addition & 1 deletion suite-common/wallet-utils/src/sendFormUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export const prepareEthereumTransaction = (txInfo: EthTransactionData) => {
chainId: txInfo.chainId,
nonce: numberToHex(txInfo.nonce),
gasLimit: numberToHex(txInfo.gasLimit),
gasPrice: numberToHex(toWei(txInfo.gasPrice, 'gwei')),
gasPrice: numberToHex(toWei(txInfo.gasPrice || '0', 'gwei')),
};

if (!txInfo.token && txInfo.data) {
Expand Down
2 changes: 1 addition & 1 deletion suite-native/module-send/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { NetworkSymbol } from '@suite-common/wallet-config';

export type StatefulReviewOutput = ReviewOutput & { state: ReviewOutputState };

export type NativeSupportedFeeLevel = Exclude<FeeLevelLabel, 'low'>;
export type NativeSupportedFeeLevel = Exclude<FeeLevelLabel, 'low' | 'medium'>;

export type SendAmountInputProps = {
recipientIndex: number;
Expand Down

0 comments on commit 5bfb927

Please sign in to comment.