Skip to content

Commit

Permalink
fix(staking): improve fee estimation and error handling in delegation…
Browse files Browse the repository at this point in the history
… modals

- Add proper cleanup of previous fee estimation requests
- Fix race conditions in fee estimation
- Add proper error state handling for amount validation
- Remove unnecessary console.logs
- Add missing dependency arrays in useEffect hooks
  • Loading branch information
olegshilov committed Dec 7, 2024
1 parent 9476a14 commit 1678858
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 101 deletions.
69 changes: 41 additions & 28 deletions libs/staking/src/lib/components/delegate-modal-hooked.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,16 @@ export function DelegateModalHooked({
setDelegateEnabled(false);
setAmountError('max');
setFee(undefined);
if (cancelPreviousRequest.current) {
cancelPreviousRequest.current();
cancelPreviousRequest.current = null;
}
setFeePending(false);
} else {
setDelegateEnabled(true);
setAmountError(undefined);
}
}, [balance, delegateAmount, fee]);
}, [balance, delegateAmount, cancelPreviousRequest]);

useEffect(() => {
if (!isOpen) {
Expand All @@ -235,45 +240,53 @@ export function DelegateModalHooked({
}, [delegateAmount, setDeboundecDelegateAmount]);

useEffect(() => {
if (isDelegateEnabled) {
if (debouncedDelegateAmount && debouncedDelegateAmount > 0) {
if (cancelPreviousRequest.current) {
cancelPreviousRequest.current();
}
if (isDelegateEnabled && debouncedDelegateAmount) {
if (debouncedDelegateAmount <= 0 || debouncedDelegateAmount > balance) {
setFee(undefined);
setFeePending(false);
return;
}

let isCancelled = false;
if (cancelPreviousRequest.current) {
cancelPreviousRequest.current();
}

cancelPreviousRequest.current = () => {
isCancelled = true;
};
let isCancelled = false;

setFeePending(true);
getDelegateEstimatedFee(
validatorAddress,
debouncedDelegateAmount,
shouldUsePrecompile,
)
.then((estimatedFee) => {
console.log('Estimated fee', { estimatedFee });
if (!isCancelled) {
setFee(estimatedFee);
setFeePending(false);
}
})
.catch((error) => {
cancelPreviousRequest.current = () => {
isCancelled = true;
};

setFeePending(true);
getDelegateEstimatedFee(
validatorAddress,
debouncedDelegateAmount,
shouldUsePrecompile,
)
.then((estimatedFee) => {
if (!isCancelled) {
setFee(estimatedFee);
setFeePending(false);
}
})
.catch((error) => {
if (!isCancelled) {
const message = (error as Error).message;
toast.error(<ToastError>{message}</ToastError>);
setFee(undefined);
setFeePending(false);
});
}
}
});
}
}, [
validatorAddress,
balance,
cancelPreviousRequest,
debouncedDelegateAmount,
getDelegateEstimatedFee,
isDelegateEnabled,
validatorAddress,
cancelPreviousRequest,
toast,
explorerLink,
]);

return (
Expand Down
107 changes: 60 additions & 47 deletions libs/staking/src/lib/components/redelegate-modal-hooked.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export function RedelegateModalHooked({
const [memo, setMemo] = useState('');
const invalidateQueries = useQueryInvalidate();
const explorerLink = shouldUsePrecompile ? explorer.evm : explorer.cosmos;
const [amountError, setAmountError] = useState<string | undefined>(undefined);

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable amountError.

const handleApprove = useCallback(async () => {
try {
Expand Down Expand Up @@ -216,27 +217,28 @@ export function RedelegateModalHooked({
}, [validatorsList, validatorAddress]);

useEffect(() => {
if (redelegateAmount) {
const delegationNumber = Number.parseFloat(
formatUnits(BigInt(delegation), 18),
);
const fixedDelegation = toFixedAmount(delegationNumber, 3) ?? 0;

if (
!(fixedDelegation > 0) ||
redelegateAmount <= 0 ||
redelegateAmount > fixedDelegation
) {
setRedelegateEnabled(false);
setFee(undefined);
} else {
setRedelegateEnabled(true);
}
} else {
if (!redelegateAmount) {
setRedelegateEnabled(false);
setAmountError(undefined);
setFee(undefined);
} else if (redelegateAmount <= 0) {
setRedelegateEnabled(false);
setAmountError('min');
setFee(undefined);
} else if (redelegateAmount > Number(formatUnits(delegation, 18))) {
setRedelegateEnabled(false);
setAmountError('max');
setFee(undefined);
if (cancelPreviousRequest.current) {
cancelPreviousRequest.current();
cancelPreviousRequest.current = null;
}
setFeePending(false);
} else {
setRedelegateEnabled(true);
setAmountError(undefined);
}
}, [redelegateAmount, delegation]);
}, [delegation, redelegateAmount, cancelPreviousRequest]);

useEffect(() => {
if (!isOpen) {
Expand All @@ -251,51 +253,62 @@ export function RedelegateModalHooked({
}, [isOpen]);

useEffect(() => {
if (isRedelegateEnabled) {
if (
isRedelegateEnabled &&
debouncedRedelegateAmount &&
validatorDestinationAddress
) {
if (
debouncedRedelegateAmount &&
debouncedRedelegateAmount > 0 &&
validatorDestinationAddress
debouncedRedelegateAmount <= 0 ||
debouncedRedelegateAmount > Number(formatUnits(delegation, 18))
) {
if (cancelPreviousRequest.current) {
cancelPreviousRequest.current();
}
setFee(undefined);
setFeePending(false);
return;
}

let isCancelled = false;
if (cancelPreviousRequest.current) {
cancelPreviousRequest.current();
}

cancelPreviousRequest.current = () => {
isCancelled = true;
};
let isCancelled = false;

setFeePending(true);
getRedelegateEstimatedFee(
validatorAddress,
validatorDestinationAddress,
debouncedRedelegateAmount,
shouldUsePrecompile,
)
.then((estimatedFee) => {
console.log('Estimated fee', { estimatedFee });
if (!isCancelled) {
setFee(estimatedFee);
setFeePending(false);
}
})
.catch((error) => {
cancelPreviousRequest.current = () => {
isCancelled = true;
};

setFeePending(true);
getRedelegateEstimatedFee(
validatorAddress,
validatorDestinationAddress,
debouncedRedelegateAmount,
shouldUsePrecompile,
)
.then((estimatedFee) => {
if (!isCancelled) {
setFee(estimatedFee);
setFeePending(false);
}
})
.catch((error) => {
if (!isCancelled) {
const message = (error as Error).message;
toast.error(<ToastError>{message}</ToastError>);
setFee(undefined);
setFeePending(false);
});
}
}
});
}
}, [
validatorAddress,
validatorDestinationAddress,
delegation,
cancelPreviousRequest,
debouncedRedelegateAmount,
validatorDestinationAddress,
getRedelegateEstimatedFee,
isRedelegateEnabled,
toast,
explorerLink,
]);

useEffect(() => {
Expand Down
67 changes: 41 additions & 26 deletions libs/staking/src/lib/components/undelegate-modal-hooked.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,16 @@ export function UndelegateModalHooked({
setUndelegateEnabled(false);
setAmountError('max');
setFee(undefined);
if (cancelPreviousRequest.current) {
cancelPreviousRequest.current();
cancelPreviousRequest.current = null;
}
setFeePending(false);
} else {
setUndelegateEnabled(true);
setAmountError(undefined);
}
}, [delegation, undelegateAmount]);
}, [delegation, undelegateAmount, cancelPreviousRequest]);

useEffect(() => {
if (!isOpen) {
Expand All @@ -220,40 +225,50 @@ export function UndelegateModalHooked({
}, [isOpen]);

useEffect(() => {
if (isUndelegateEnabled) {
if (debouncedUndelegateAmount && debouncedUndelegateAmount > 0) {
if (cancelPreviousRequest.current) {
cancelPreviousRequest.current();
}
if (isUndelegateEnabled && debouncedUndelegateAmount) {
if (
debouncedUndelegateAmount <= 0 ||
debouncedUndelegateAmount > delegation
) {
setFee(undefined);
setFeePending(false);
return;
}

let isCancelled = false;
if (cancelPreviousRequest.current) {
cancelPreviousRequest.current();
}

let isCancelled = false;

cancelPreviousRequest.current = () => {
isCancelled = true;
};
cancelPreviousRequest.current = () => {
isCancelled = true;
};

setFeePending(true);
getUndelegateEstimatedFee(
validatorAddress,
debouncedUndelegateAmount,
shouldUsePrecompile,
)
.then((estimatedFee) => {
console.log('Estimated fee', { estimatedFee });
if (!isCancelled) {
setFee(estimatedFee);
setFeePending(false);
}
})
.catch((error) => {
setFeePending(true);
getUndelegateEstimatedFee(
validatorAddress,
debouncedUndelegateAmount,
shouldUsePrecompile,
)
.then((estimatedFee) => {
if (!isCancelled) {
setFee(estimatedFee);
setFeePending(false);
}
})
.catch((error) => {
if (!isCancelled) {
const message = (error as Error).message;
toast.error(<ToastError>{message}</ToastError>);
setFee(undefined);
setFeePending(false);
});
}
}
});
}
}, [
validatorAddress,
delegation,
cancelPreviousRequest,
debouncedUndelegateAmount,
getUndelegateEstimatedFee,
Expand Down

0 comments on commit 1678858

Please sign in to comment.