Skip to content

Commit

Permalink
wip: priority
Browse files Browse the repository at this point in the history
  • Loading branch information
enjojoy committed Feb 3, 2025
1 parent fdbbbbf commit 9062eec
Show file tree
Hide file tree
Showing 20 changed files with 597 additions and 223 deletions.
22 changes: 22 additions & 0 deletions packages/blockchain-link-types/src/blockbook-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,10 +415,32 @@ export interface WsEstimateFeeReq {
value?: string;
};
}

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

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

export interface WsEstimateFeeRes {
feePerTx?: string;
feePerUnit?: string;
feeLimit?: string;
eip1559?: {
baseFeePerGas: string;
high: PriorityFeeEstimationDetails;
low: PriorityFeeEstimationDetails;
medium: PriorityFeeEstimationDetails;
networkCongestion: number;
latestPriorityFeeRange: string[];
historicalPriorityFeeRange: string[];
historicalBaseFeeRange: string[];
priorityFeeTrend: FeeTrend;
baseFeeTrend: FeeTrend;
};
}
export interface WsSendTransactionReq {
hex: string;
Expand Down
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
50 changes: 37 additions & 13 deletions packages/connect/src/api/bitcoin/Fees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,43 @@ export class FeeLevels {
async loadMisc(blockchain: Blockchain) {
try {
const [response] = await blockchain.estimateFee({ blocks: [1] });
// 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(),
};
if (response.eip1559) {
const eip1559LevelKeys = ['low', 'medium', 'high'] as const;

const { eip1559 } = 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 / 1000, // Infura provides wait time in miliseconds
maxWaitTimeEstimate: level.maxWaitTimeEstimate / 1000,
feePerUnit: '0',
feeLimit: undefined,
ethFeeType: 'eip1559' as const,
blocks: -1,
};
});

this.levels = [...eip1559Levels];
} else {
//misc coins should have only one FeeLevel (normal), for ethereum depends on availability of eip1559
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
17 changes: 16 additions & 1 deletion packages/connect/src/types/fees.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Static, Type } from '@trezor/schema-utils';
import { Type, Static } from '@trezor/schema-utils';

Check warning on line 1 in packages/connect/src/types/fees.ts

View workflow job for this annotation

GitHub Actions / Linting and formatting

Member 'Static' of the import declaration should be sorted alphabetically

export type FeeInfo = Static<typeof FeeInfo>;
export const FeeInfo = Type.Object({
Expand All @@ -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
80 changes: 63 additions & 17 deletions packages/suite/src/components/wallet/Fees/CustomFee.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ import { useSelector, useTranslation } from 'src/hooks/suite';
import { selectLanguage } from 'src/reducers/suite/suiteReducer';
import { validateDecimals } from 'src/utils/suite/validation';

import { BorderTopWrapper } from './Fees';
import { InputError } from '../InputError';

const FEE_PER_UNIT = 'feePerUnit';
const FEE_LIMIT = 'feeLimit';

const MAX_FEE_PER_GAS = 'maxFeePerGas';
const MAX_PRIORITY_FEE_PER_GAS = 'maxPriorityFeePerGas';

interface CustomFeeProps<TFieldValues extends FormState> {
networkType: NetworkType;
feeInfo: FeeInfo;
Expand All @@ -50,6 +52,7 @@ interface CustomFeeProps<TFieldValues extends FormState> {
setValue: UseFormSetValue<TFieldValues>;
getValues: UseFormGetValues<TFieldValues>;
composedFeePerByte: string;
shouldUsePriorityFees?: boolean;
}

const getAverageFee = (levels: FeeLevel[]) => `${levels[levels.length > 2 ? 1 : 0].feePerUnit}`;
Expand All @@ -60,13 +63,16 @@ export const CustomFee = <TFieldValues extends FormState>({
register,
control,
composedFeePerByte,
shouldUsePriorityFees = false,
...props
}: CustomFeeProps<TFieldValues>) => {
const { translationString } = useTranslation();
const isBelowLaptop = useMediaQuery(`(max-width: ${variables.SCREEN_SIZE.LG})`);

const locale = useSelector(selectLanguage);

console.log('feeInfo', feeInfo);

// Type assertion allowing to make the component reusable, see https://stackoverflow.com/a/73624072.
const { getValues, setValue } = props as unknown as UseFormReturn<FormState>;
const errors = props.errors as unknown as FieldErrors<FormState>;
Expand All @@ -77,9 +83,13 @@ export const CustomFee = <TFieldValues extends FormState>({
const feeUnits = getFeeUnits(networkType);
const estimatedFeeLimit = getValues('estimatedFeeLimit');

// const maxFeePerGas = shouldUsePriorityFees ? getValues(MAX_FEE_PER_GAS) : undefined; //only for priority fees on evms
// const maxPriorityFeePerGas = shouldUsePriorityFees
// ? getValues(MAX_PRIORITY_FEE_PER_GAS)
// : undefined;

const feePerUnitError = errors.feePerUnit;
const feeLimitError = errors.feeLimit;
const { elevation } = useElevation();

const useFeeLimit = networkType === 'ethereum';
const isComposedFeeRateDifferent =
Expand Down Expand Up @@ -219,21 +229,57 @@ export const CustomFee = <TFieldValues extends FormState>({
) : (
<input type="hidden" {...register(FEE_LIMIT as FieldPath<TFieldValues>)} />
)}
<NumberInput
label={useFeeLimit ? <Translation id="TR_GAS_PRICE" /> : undefined}
locale={locale}
control={control}
inputState={getInputState(feePerUnitError)}
innerAddon={
<Text variant="tertiary" typographyStyle="label">
{feeUnits}
</Text>
}
name={FEE_PER_UNIT}
data-testid={FEE_PER_UNIT}
rules={feeRules}
bottomText={feePerUnitError?.message || null}
/>

{shouldUsePriorityFees && feeInfo.levels[0].ethFeeType === 'eip1559' ? (
<>
<NumberInput
label={<Translation id="TR_MAX_PRIORITY_FEE_PER_GAS" />}
locale={locale}
control={control}
inputState={getInputState(feePerUnitError)}
innerAddon={
<Text variant="tertiary" typographyStyle="label">
{feeUnits}
</Text>
}
name={MAX_PRIORITY_FEE_PER_GAS}
data-testid={MAX_PRIORITY_FEE_PER_GAS}
rules={feeRules}
bottomText={feePerUnitError?.message || null}
/>
<NumberInput
label={<Translation id="TR_MAX_FEE_PER_GAS" />}
locale={locale}
control={control}
inputState={getInputState(feePerUnitError)}
innerAddon={
<Text variant="tertiary" typographyStyle="label">
{feeUnits}
</Text>
}
name={MAX_FEE_PER_GAS}
data-testid={MAX_FEE_PER_GAS}
rules={feeRules}
bottomText={feePerUnitError?.message || null}
/>
</>
) : (
<NumberInput
label={useFeeLimit ? <Translation id="TR_GAS_PRICE" /> : undefined}
locale={locale}
control={control}
inputState={getInputState(feePerUnitError)}
innerAddon={
<Text variant="tertiary" typographyStyle="label">
{feeUnits}
</Text>
}
name={FEE_PER_UNIT}
data-testid={FEE_PER_UNIT}
rules={feeRules}
bottomText={feePerUnitError?.message || null}
/>
)}
</Grid>
{feeDifferenceWarning && <Note>{feeDifferenceWarning}</Note>}
</Column>
Expand Down
Loading

0 comments on commit 9062eec

Please sign in to comment.