Skip to content

Commit

Permalink
fix: Send screen more stable (#1783)
Browse files Browse the repository at this point in the history
- Closes #1770 
- Closes FE-1300
  • Loading branch information
LuizAsFight authored Jan 20, 2025
1 parent 5399a35 commit 5680b65
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 28 deletions.
5 changes: 5 additions & 0 deletions .changeset/two-starfishes-double.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"fuels-wallet": patch
---

fix: make send screen flows more stable by relying less on form changes
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,21 @@ export function createAmount(text: string, units = 0) {

let amount: BN | undefined;
if (isZeroUnits) {
const textWithoutDecimals = textAmountFixed
.replaceAll(',', '')
.split('.')[0];
amount = bn(textWithoutDecimals);
const integerPart = textAmountFixed.replaceAll(',', '').split('.')?.[0];
amount = bn(integerPart);
} else {
amount = bn.parseUnits(textAmountFixed.replaceAll(',', ''), units);
// get value after fraction, remove extra decimals
const textWithoutComma = textAmountFixed.replaceAll(',', '');
const textIntegerPart = textWithoutComma.split('.')[0];
const fractionWithoutExtraDecimals = textWithoutComma
.split('.')?.[1]
?.slice(0, units);
const textWithoutExtraDecimals = textIntegerPart
? `${textIntegerPart}${
fractionWithoutExtraDecimals ? `.${fractionWithoutExtraDecimals}` : ''
}`
: '';
amount = bn.parseUnits(textWithoutExtraDecimals, units);
}

return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { InputNumberProps } from '@fuel-ui/react';

export const isAmountAllowed: InputNumberProps['isAllowed'] = ({ value }) => {
console.log(value);
// Allow to clear the input
if (!value) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export function SendSelect({
errorMessage,
warningMessage,
provider,
handlers,
}: SendSelectProps) {
const [watchMax, setWatchMax] = useState(false);
const isAmountFocused = useRef<boolean>(false);
Expand Down Expand Up @@ -74,7 +75,9 @@ export function SendSelect({
const maxFee = baseFee.add(tip).add(1);
if (maxFee.gt(balanceAssetSelected)) return;

form.setValue('amount', balanceAssetSelected.sub(maxFee));
const newAmount = balanceAssetSelected.sub(maxFee);
form.setValue('amount', newAmount);
handlers.recalculateFromAmount(newAmount);
}
}, [
watchMax,
Expand Down Expand Up @@ -167,6 +170,7 @@ export function SendSelect({
setWatchMax(true);
} else {
form.setValue('amount', balanceAssetSelected);
handlers.recalculateFromAmount(balanceAssetSelected);
}
}}
inputProps={{
Expand Down Expand Up @@ -203,6 +207,7 @@ export function SendSelect({
gasLimit={gasLimit}
regularTip={regularTip}
fastTip={fastTip}
onRecalculate={handlers.recalculateFromTip}
/>
</MotionStack>
)}
Expand Down
43 changes: 38 additions & 5 deletions packages/app/src/systems/Send/hooks/useSend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ const selectors = {

return state.context.error;
},
input(state: SendMachineState) {
return state.context.input;
},
status(txStatus?: TxRequestStatus) {
return useCallback(
(state: SendMachineState) => {
Expand Down Expand Up @@ -102,9 +105,10 @@ const schemaFactory = (provider?: Provider) =>
return false;
}

const baseAssetId = await provider?.getBaseAssetId();

const isSendingBaseAssetId =
asset &&
provider?.getBaseAssetId().toLowerCase() === asset.toLowerCase();
asset && baseAssetId?.toLowerCase() === asset.toLowerCase();
if (isSendingBaseAssetId) {
// It means "baseFee" is being calculated
if (!baseFee) {
Expand Down Expand Up @@ -141,7 +145,7 @@ const schemaFactory = (provider?: Provider) =>
}

const assetCached = await AssetsCache.getInstance().getAsset({
chainId: provider.getChainId(),
chainId: await provider.getChainId(),
assetId: value,
dbAssets: [],
save: false,
Expand Down Expand Up @@ -345,6 +349,7 @@ export function useSend() {
const sendStatusSelector = selectors.status(txRequest.txStatus);
const sendStatus = useSelector(service, sendStatusSelector);
const readyToSend = useSelector(service, selectors.readyToSend);
const input = useSelector(service, selectors.input);

const balanceAssetSelected = useMemo<BN>(() => {
const asset = account?.balances?.find(
Expand Down Expand Up @@ -374,9 +379,8 @@ export function useSend() {
function tryAgain() {
txRequest.handlers.tryAgain();
}

useEffect(() => {
const { unsubscribe } = form.watch(() => {
const { unsubscribe } = form.watch((_data, { name: _, type }) => {
const { address, asset, amount } = form.getValues();
if (address) {
form.trigger('address');
Expand All @@ -385,6 +389,12 @@ export function useSend() {
return;
}

// skip the form trigger if the user is not directly changing the form.
// this is to avoid the form being used to control start of flows, other than user typing.
if (type !== 'change') {
return;
}

form.handleSubmit((data) => {
const { address, asset, amount, fees } = data;

Expand All @@ -410,6 +420,27 @@ export function useSend() {
service.send,
]);

const recalculateFromTip = (tip: BN) => {
service.send('SET_INPUT', { input: { ...input, tip } });
form.trigger('amount');
};

const recalculateFromAmount = (amount: BN) => {
let previousInput = input;
if (!input) {
const { address, asset, fees } = form.getValues();
previousInput = {
to: address,
assetId: asset,
amount,
tip: fees.tip.amount,
gasLimit: fees.gasLimit.amount,
};
}
service.send('SET_INPUT', { input: { ...previousInput, amount } });
form.trigger('amount');
};

return {
form,
baseFee,
Expand All @@ -431,6 +462,8 @@ export function useSend() {
submit,
goHome,
tryAgain,
recalculateFromTip,
recalculateFromAmount,
},
};
}
Expand Down
16 changes: 1 addition & 15 deletions packages/app/src/systems/Send/machines/sendMachine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export const sendMachine = createMachine(
},
{
actions: ['assignTransactionData'],
target: 'waitingToAllowSending',
target: 'readyToSend',
},
],
},
Expand All @@ -149,20 +149,6 @@ export const sendMachine = createMachine(
},
},
},
// @TODO: "waitingToAllowSending" only exists to allow the useEffect on useSend to trigger, avoiding an error where the review button was enabled and then in loading state right after
waitingToAllowSending: {
on: {
SET_INPUT: {
actions: ['assignInput'],
target: 'changingInput',
},
},
after: {
500: {
target: 'readyToSend',
},
},
},
readyToSend: {
on: {
CONFIRM: { actions: ['callTransactionRequest'] },
Expand Down
4 changes: 3 additions & 1 deletion packages/app/src/systems/Send/pages/SendPage/SendPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export function SendPage() {
setWarningMessage(undefined);
}, [address]);

const hasFormErrors = Object.keys(form.formState.errors).length > 0;

return (
<FormProvider {...form}>
<form
Expand All @@ -58,7 +60,7 @@ export function SendPage() {
<Button
type="submit"
intent="primary"
isDisabled={!readyToSend || !form.formState.isValid}
isDisabled={!readyToSend || hasFormErrors}
isLoading={status('loading') || status('loadingTx')}
>
Review
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type TxFeeOptionsProps = {
gasLimit: BN;
regularTip: BN;
fastTip: BN;
onRecalculate?: (tip: BN) => void;
};

export const TxFeeOptions = ({
Expand All @@ -28,6 +29,7 @@ export const TxFeeOptions = ({
gasLimit: gasLimitInput,
regularTip,
fastTip,
onRecalculate,
}: TxFeeOptionsProps) => {
const { control, setValue, getValues } = useFormContext<SendFormValues>();
const [isAdvanced, setIsAdvanced] = useState(initialAdvanced);
Expand Down Expand Up @@ -181,6 +183,7 @@ export const TxFeeOptions = ({
amount: option.tip,
text: formatTip(option.tip),
});
onRecalculate?.(option.tip);
}}
/>
))}
Expand Down

0 comments on commit 5680b65

Please sign in to comment.