Skip to content

Commit 117e4dd

Browse files
committed
feat(suite-native): add dynamic error msgs to feeFormSchema
1 parent 1da6ebe commit 117e4dd

File tree

3 files changed

+177
-63
lines changed

3 files changed

+177
-63
lines changed

suite-native/intl/src/messages.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2787,6 +2787,24 @@ export const messages = {
27872787
maxFeePerGas: 'Max fee per gas',
27882788
maxPriorityFeePerGas: 'Max priority fee per gas',
27892789
},
2790+
errors: {
2791+
feeLimit: {
2792+
low: 'Value is too low.',
2793+
},
2794+
decimals: 'Too many decimals.',
2795+
feePerUnit: {
2796+
low: 'Fee is too low.',
2797+
high: 'Fee is too high.',
2798+
},
2799+
maxFeePerGas: {
2800+
lessThanPriority: 'This fee can’t be lower than Max priority fee.',
2801+
outOfRange: 'Enter a max fee per gas between {minFee} and {maxFee}',
2802+
},
2803+
maxPriorityFee: {
2804+
min: 'Max priority fee must be at least {minPriorityFee}',
2805+
higherThanMaxFee: 'This fee can’t be higher than Max fee per gas',
2806+
},
2807+
},
27902808
total: 'Total fee',
27912809
confirmButton: 'Confirm custom fee',
27922810
},

suite-native/transaction-management/src/feesFormSchema.ts

Lines changed: 155 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { NetworkSymbol, getNetwork } from '@suite-common/wallet-config';
33
import { FeeInfo, FeeLevelLabel } from '@suite-common/wallet-types';
44
import { isDecimalsValid } from '@suite-common/wallet-utils';
55
import type { UseFormReturn } from '@suite-native/forms';
6+
import { Translate } from '@suite-native/intl';
67
import { BigNumber } from '@trezor/utils';
78

89
import { getFeeDecimals } from './utils';
@@ -11,14 +12,12 @@ export type FeesFormContext = {
1112
symbol?: NetworkSymbol;
1213
networkFeeInfo?: FeeInfo;
1314
minimalFeeLimit?: string;
15+
translate?: Translate;
1416
};
1517

1618
const FeeLevelLabels: Array<FeeLevelLabel> = ['economy', 'low', 'normal', 'high', 'custom'];
1719

18-
const createFeeDecimalsTest = (
19-
value: string | undefined,
20-
{ options: { context } }: yup.TestContext<FeesFormContext>,
21-
) => {
20+
const validateFeeDecimalLength = (value: string | undefined, context: FeesFormContext) => {
2221
if (!value) return true;
2322

2423
const { networkFeeInfo, symbol } = context!;
@@ -36,96 +35,189 @@ const createFeeDecimalsTest = (
3635
return isDecimalsValid(value, maxDecimals);
3736
};
3837

39-
const createFeeValidation = () =>
40-
yup
38+
export const feesFormValidationSchema = yup.object({
39+
feeLevel: yup.string().oneOf(FeeLevelLabels).required('Fee level is required'),
40+
customFeePerUnit: yup
4141
.string()
42-
.test('too-many-decimals', 'Too many decimals.', createFeeDecimalsTest)
43-
.test(
44-
'fee-too-low',
45-
'Fee is too low.',
46-
(value, { options: { context } }: yup.TestContext<FeesFormContext>) => {
47-
if (!value) return true;
48-
const { networkFeeInfo } = context!;
42+
.test('too-many-decimals', 'Too many decimals.', function (value) {
43+
const { translate, ...context } = this.options.context as FeesFormContext;
44+
if (!validateFeeDecimalLength(value, context)) {
45+
return this.createError({
46+
message: translate!(
47+
'transactionManagement.fees.custom.bottomSheet.errors.decimals',
48+
),
49+
});
50+
}
51+
52+
return true;
53+
})
54+
.test('fee-too-low', 'Fee is too low.', function (value) {
55+
if (!value) return true;
56+
const { networkFeeInfo, translate } = this.options.context as FeesFormContext;
57+
58+
if (!networkFeeInfo) return false;
59+
const { minFee } = networkFeeInfo;
60+
61+
if (Number(value) < minFee) {
62+
return this.createError({
63+
message: translate!(
64+
'transactionManagement.fees.custom.bottomSheet.errors.feePerUnit.low',
65+
),
66+
});
67+
}
68+
69+
return true;
70+
})
71+
.test('fee-too-high', 'Fee is too high.', function (value) {
72+
const { networkFeeInfo, translate } = this.options.context as FeesFormContext;
73+
74+
if (!value || !networkFeeInfo) return false;
75+
76+
const feeBig = new BigNumber(value);
77+
const { maxFee } = networkFeeInfo;
78+
79+
if (feeBig.gt(maxFee)) {
80+
return this.createError({
81+
message: translate!(
82+
'transactionManagement.fees.custom.bottomSheet.errors.feePerUnit.high',
83+
),
84+
});
85+
}
86+
87+
return true;
88+
})
89+
.required(),
90+
customFeeLimit: yup.string().test(
91+
'fee-limit-too-low',
92+
'Value is too low.',
4993

50-
if (!networkFeeInfo) return false;
51-
const { minFee } = networkFeeInfo;
94+
function (value) {
95+
const { symbol, minimalFeeLimit, translate } = this.options.context as FeesFormContext;
5296

53-
return Number(value) >= minFee;
54-
},
55-
)
56-
.test(
57-
'fee-too-high',
58-
'Fee is too high.',
59-
(value, { options: { context } }: yup.TestContext<FeesFormContext>) => {
60-
if (!value) return true;
97+
if (!symbol) return true;
6198

62-
const { networkFeeInfo } = context!;
99+
const { networkType } = getNetwork(symbol);
63100

64-
if (!value || !networkFeeInfo) return false;
101+
// Fee limit is used only for Ethereum, pass this validation for other networks.
102+
if (networkType !== 'ethereum') return true;
65103

66-
const feeBig = new BigNumber(value);
67-
const { maxFee } = networkFeeInfo;
104+
if (!value || !minimalFeeLimit) return false;
68105

69-
return feeBig.lte(maxFee);
70-
},
71-
);
106+
const feeBig = new BigNumber(value);
72107

73-
export const feesFormValidationSchema = yup.object({
74-
feeLevel: yup.string().oneOf(FeeLevelLabels).required('Fee level is required'),
75-
customFeePerUnit: createFeeValidation().required(),
76-
customFeeLimit: yup
108+
if (feeBig.isLessThan(minimalFeeLimit)) {
109+
return this.createError({
110+
message: translate!(
111+
'transactionManagement.fees.custom.bottomSheet.errors.feeLimit.low',
112+
),
113+
});
114+
}
115+
116+
return true;
117+
},
118+
),
119+
// EIP1559 only validations
120+
customMaxFeePerGas: yup
77121
.string()
122+
.test('too-many-decimals', 'Too many decimals.', function (value) {
123+
const { translate, ...context } = this.options.context as FeesFormContext;
124+
if (!validateFeeDecimalLength(value, context)) {
125+
return this.createError({
126+
message: translate!(
127+
'transactionManagement.fees.custom.bottomSheet.errors.decimals',
128+
),
129+
});
130+
}
131+
132+
return true;
133+
})
134+
.test('max-fee-per-gas-range', 'Max fee per gas is out of range.', function (value) {
135+
const { translate, networkFeeInfo } = this.options.context as FeesFormContext;
136+
if (!value || !networkFeeInfo) return false;
137+
138+
const { maxFee, minFee } = networkFeeInfo;
139+
140+
if (Number(value) > Number(maxFee) || Number(value) < Number(minFee)) {
141+
return this.createError({
142+
message: translate!(
143+
'transactionManagement.fees.custom.bottomSheet.errors.maxFeePerGas.outOfRange',
144+
{
145+
minFee,
146+
maxFee,
147+
},
148+
),
149+
});
150+
}
151+
152+
return true;
153+
})
78154
.test(
79-
'fee-limit-too-low',
80-
'Value is too low.',
81-
(value, { options: { context } }: yup.TestContext<FeesFormContext>) => {
82-
const { symbol, minimalFeeLimit } = context!;
83-
if (!symbol) return true;
155+
'custom-max-fee-per-gas-higher-than-priority',
156+
'Max fee must be higher than priority fee.',
157+
function (value) {
158+
if (!value) return true;
84159

85-
const { networkType } = getNetwork(symbol);
160+
const { customMaxPriorityFeePerGas } = this.parent;
86161

87-
// Fee limit is used only for Ethereum, pass this validation for other networks.
88-
if (networkType !== 'ethereum') return true;
162+
if (!customMaxPriorityFeePerGas) return true;
89163

90-
if (!value || !minimalFeeLimit) return false;
164+
const { translate } = this.options.context as FeesFormContext;
91165

92-
const feeBig = new BigNumber(value);
166+
if (Number(value) < Number(customMaxPriorityFeePerGas)) {
167+
return this.createError({
168+
message: translate!(
169+
'transactionManagement.fees.custom.bottomSheet.errors.maxFeePerGas.lessThanPriority',
170+
),
171+
});
172+
}
93173

94-
return feeBig.gte(minimalFeeLimit);
174+
return true;
95175
},
96176
),
97-
// EIP1559 only validations
98-
customMaxFeePerGas: createFeeValidation().test(
99-
'custom-max-fee-per-gas-higher-than-priority',
100-
'Max fee must be higher than or equal to priority fee.',
101-
function (value) {
102-
if (!value) return true;
103-
104-
const { customMaxPriorityFeePerGas } = this.parent;
105-
106-
if (!customMaxPriorityFeePerGas) return true;
107-
108-
return Number(value) > Number(customMaxPriorityFeePerGas);
109-
},
110-
),
111177
customMaxPriorityFeePerGas: yup
112178
.string()
113-
.test('too-many-decimals', 'Too many decimals.', createFeeDecimalsTest)
179+
.test('too-many-decimals', 'Too many decimals.', function (value) {
180+
const { translate, ...context } = this.options.context as FeesFormContext;
181+
if (!validateFeeDecimalLength(value, context)) {
182+
return this.createError({
183+
message: translate!(
184+
'transactionManagement.fees.custom.bottomSheet.errors.decimals',
185+
),
186+
});
187+
}
188+
189+
return true;
190+
})
114191
.test(
115192
'custom-priority-fee-per-gas',
116193
'Priority fee higher than max fee or below minimum.',
117194
function (value) {
118195
if (!value) return true;
119-
const { networkFeeInfo } = this.options.context!;
196+
const { networkFeeInfo, translate } = this.options.context as FeesFormContext;
120197

121198
if (!networkFeeInfo) return false;
122199
const { minPriorityFee } = networkFeeInfo;
123200

124-
if (Number(value) < minPriorityFee) return false;
201+
if (Number(value) < minPriorityFee) {
202+
return this.createError({
203+
message: translate!(
204+
'transactionManagement.fees.custom.bottomSheet.errors.maxPriorityFee.min',
205+
{ minPriorityFee },
206+
),
207+
});
208+
}
125209

126210
const { customMaxFeePerGas } = this.parent;
127211

128-
return !(customMaxFeePerGas && Number(value) > Number(customMaxFeePerGas));
212+
if (customMaxFeePerGas && Number(value) > Number(customMaxFeePerGas)) {
213+
return this.createError({
214+
message: translate!(
215+
'transactionManagement.fees.custom.bottomSheet.errors.maxPriorityFee.higherThanMaxFee',
216+
),
217+
});
218+
}
219+
220+
return true;
129221
},
130222
),
131223
});

suite-native/transaction-management/src/hooks/fees/useFeesForm.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
isFinalPrecomposedTransaction,
1414
} from '@suite-common/wallet-types';
1515
import { useForm } from '@suite-native/forms';
16+
import { useTranslate } from '@suite-native/intl';
1617

1718
import { FeesFormValues, feesFormValidationSchema } from '../../feesFormSchema';
1819
import { selectFeeLevels } from '../../selectors';
@@ -33,6 +34,8 @@ export const useFeesForm = ({
3334
selectAccountByKey(state, accountKey),
3435
);
3536

37+
const { translate } = useTranslate();
38+
3639
const feeLevels = useSelector(selectFeeLevels);
3740

3841
const networkFeeInfo = useSelector((state: FeesRootState) =>
@@ -64,6 +67,7 @@ export const useFeesForm = ({
6467
networkFeeInfo,
6568
symbol: account?.symbol,
6669
minimalFeeLimit,
70+
translate,
6771
},
6872
});
6973
};

0 commit comments

Comments
 (0)