Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: LowGasAlert errors on EVM #7782

Merged
merged 5 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/late-seals-buy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ledger-live-desktop": minor
---

refactor: LowGasAlert to be consistent with all other errors
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useCallback } from "react";
import { useHistory } from "react-router-dom";
import { useDispatch } from "react-redux";
import { setTrackingSource } from "~/renderer/analytics/TrackPage";
import { isCurrencySupported } from "~/renderer/screens/exchange/config";
import Alert from "~/renderer/components/Alert";
import { Account } from "@ledgerhq/types-live/lib/account";
import { Flex } from "@ledgerhq/react-ui";
import TranslatedError from "~/renderer/components/TranslatedError";

type LowGasAlertBuyMoreProps = {
account: Account;
handleRequestClose: () => void;
gasPriceError: Error | null;
trackingSource: string;
};

/**
* LowGasAlertBuyMore
*
* This component renders an alert message when the user has insufficient gas
* to complete a transaction.
* It also provides a call to action to buy more crypto,
* handling redirection to the exchange flow.
*
* Usage:
* <LowGasAlertBuyMore
* account={mainAccount}
* handleRequestClose={closeAllModal}
* gasPriceError={gasPriceError}
* trackingSource={"swap | send or whatever"}s
* />
*
*/
const LowGasAlertBuyMore = ({
account,
handleRequestClose,
gasPriceError,
trackingSource,
}: LowGasAlertBuyMoreProps) => {
const history = useHistory();
const dispatch = useDispatch();

const onBuyClick = useCallback(() => {
dispatch(handleRequestClose());
setTrackingSource(trackingSource);
history.push({
pathname: "/exchange",
state: {
currency: account.currency.id,
account: account.id,
mode: "buy",
},
});
}, [account.currency.id, account.id, history, dispatch, handleRequestClose, trackingSource]);

if (!gasPriceError) return null;
return (
<Flex onClick={isCurrencySupported("BUY", account.currency) ? onBuyClick : undefined}>
<Alert type="warning">
<TranslatedError error={gasPriceError} />
</Alert>
</Flex>
);
};

export default LowGasAlertBuyMore;
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,11 @@ import GasPriceField from "./GasPriceField";
import MaxFeeField from "./MaxFeeField";
import PriorityFeeField from "./PriorityFeeField";
import SelectFeeStrategy from "./SelectFeeStrategy";
import TranslatedError from "~/renderer/components/TranslatedError";
import Alert from "~/renderer/components/Alert";
import { Flex } from "@ledgerhq/react-ui";
import { closeAllModal } from "~/renderer/actions/modals";
import { setTrackingSource } from "~/renderer/analytics/TrackPage";
import { useDispatch } from "react-redux";
import { useHistory } from "react-router";

const Root: NonNullable<EvmFamily["sendAmountFields"]>["component"] = props => {
const { account, updateTransaction, transaction } = props;
const bridge: AccountBridge<EvmTransaction> = getAccountBridge(account);

const { errors } = props.status;
const { gasPrice: messageGas, amount: messageAmount } = errors;
const dispatch = useDispatch();
const history = useHistory();

const onBuyClick = useCallback(() => {
dispatch(closeAllModal());
setTrackingSource("send flow");
history.push({
pathname: "/exchange",
state: {
currency: account.currency.id,
account: account.id,
mode: "buy", // buy or sell
},
});
}, [account.currency.id, account.id, dispatch, history]);

const [gasOptions, error, loading] = useGasOptions({
currency: account.currency,
transaction,
Expand Down Expand Up @@ -111,13 +86,6 @@ const Root: NonNullable<EvmFamily["sendAmountFields"]>["component"] = props => {
<SelectFeeStrategy gasOptions={gasOptions} onClick={onFeeStrategyClick} {...props} />
</>
)}
{(messageGas || messageAmount) && (
<Flex onClick={onBuyClick}>
<Alert type="warning" data-testid="alert-insufficient-funds-warning">
<TranslatedError error={messageGas || messageAmount} />
</Alert>
</Flex>
)}
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import Button from "~/renderer/components/Button";
import CurrencyDownStatusAlert from "~/renderer/components/CurrencyDownStatusAlert";
import ErrorBanner from "~/renderer/components/ErrorBanner";
import SpendableBanner from "~/renderer/components/SpendableBanner";
import BuyButton from "~/renderer/components/BuyButton";
import Label from "~/renderer/components/Label";
import Input from "~/renderer/components/Input";
import { useSelector } from "react-redux";
Expand All @@ -20,6 +19,8 @@ import SendAmountFields from "../SendAmountFields";
import AmountField from "../fields/AmountField";
import { StepProps } from "../types";
import { getLLDCoinFamily } from "~/renderer/families";
import { closeAllModal } from "~/renderer/actions/modals";
import LowGasAlertBuyMore from "~/renderer/families/evm/SendAmountFields/LowGasAlertBuyMore";

const StepAmount = (props: StepProps) => {
const {
Expand Down Expand Up @@ -60,6 +61,8 @@ const StepAmount = (props: StepProps) => {
}, [specific.nft, transaction]);

if (!status) return null;
const { errors } = status;
const { gasPrice } = errors;

return (
<Box flow={4}>
Expand Down Expand Up @@ -114,6 +117,12 @@ const StepAmount = (props: StepProps) => {
bridgePending={bridgePending}
updateTransaction={updateTransaction}
/>
<LowGasAlertBuyMore
account={mainAccount}
handleRequestClose={closeAllModal}
gasPriceError={gasPrice}
trackingSource={"send flow"}
/>
</Fragment>
</Box>
);
Expand All @@ -132,16 +141,12 @@ export class StepAmountFooter extends PureComponent<StepProps> {
const isTerminated = mainAccount.currency.terminated;
const hasErrors = Object.keys(errors).length;
const canNext = !bridgePending && !hasErrors && !isTerminated;
const { maxPriorityFee: maxPriorityFeeError, maxFee: maxFeeError } = errors;

return (
<>
{!isNFTSend ? (
<AccountFooter parentAccount={parentAccount} account={account} status={status} />
) : null}
{maxPriorityFeeError || maxFeeError ? (
<BuyButton currency={mainAccount.currency} account={mainAccount} />
) : null}
<Button
id={"send-amount-continue-button"}
isLoading={bridgePending}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import TrackPage from "~/renderer/analytics/TrackPage";
import Box from "~/renderer/components/Box";
import Button from "~/renderer/components/Button";
import CurrencyDownStatusAlert from "~/renderer/components/CurrencyDownStatusAlert";
import BuyButton from "~/renderer/components/BuyButton";
import { NotEnoughGas } from "@ledgerhq/errors";
import Alert from "~/renderer/components/Alert";
import TranslatedError from "~/renderer/components/TranslatedError";
import AccountFooter from "../AccountFooter";
import SendAmountFields from "../SendAmountFields";
import { StepProps } from "../types";
import LowGasAlertBuyMore from "~/renderer/families/evm/SendAmountFields/LowGasAlertBuyMore";
import { closeAllModal } from "~/renderer/actions/modals";
const StepAmount = ({
account,
parentAccount,
Expand All @@ -25,15 +25,19 @@ const StepAmount = ({
}: StepProps) => {
if (!status) return null;
const mainAccount = account ? getMainAccount(account, parentAccount) : null;
const { gasPrice: gasPriceError } = status.errors;

return (
<Box flow={4}>
<TrackPage category="Sign Transaction Flow" name="Step Amount" />
{mainAccount ? <CurrencyDownStatusAlert currencies={[mainAccount.currency]} /> : null}
{error || warning ? (
<Alert type={error ? "error" : "warning"}>
<TranslatedError error={error || warning} />
</Alert>
) : null}
{error || warning
? !gasPriceError && (
<Alert type={error ? "error" : "warning"}>
<TranslatedError error={error || warning} />
</Alert>
)
: null}
{account && transaction && mainAccount && (
<Fragment key={account.id}>
<SendAmountFields
Expand All @@ -47,6 +51,14 @@ const StepAmount = ({
/>
</Fragment>
)}
{mainAccount && gasPriceError && (
<LowGasAlertBuyMore
account={mainAccount}
handleRequestClose={closeAllModal}
gasPriceError={gasPriceError}
trackingSource={"sign flow"}
/>
)}
</Box>
);
};
Expand All @@ -64,13 +76,9 @@ export class StepAmountFooter extends PureComponent<StepProps> {
const isTerminated = mainAccount.currency.terminated;
const hasErrors = Object.keys(errors).length;
const canNext = !bridgePending && !hasErrors && !isTerminated;
const { gasPrice } = errors;
return (
<>
<AccountFooter parentAccount={parentAccount} account={account} status={status} />
{gasPrice && gasPrice instanceof NotEnoughGas ? (
<BuyButton currency={mainAccount.currency} account={mainAccount} />
) : null}
<Button
id={"sign-transaction-amount-continue-button"}
isLoading={bridgePending}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ import { useGetSwapTrackingProperties } from "../../utils/index";
import { Account, AccountLike, FeeStrategy } from "@ledgerhq/types-live";
import { t } from "i18next";
import { Transaction } from "@ledgerhq/live-common/generated/types";
import { Button, Divider } from "@ledgerhq/react-ui";
import { Button, Divider, Flex } from "@ledgerhq/react-ui";
import { getAccountBridge } from "@ledgerhq/live-common/bridge/impl";
import { getMainAccount } from "@ledgerhq/live-common/account/index";
import LowGasAlertBuyMore from "~/renderer/families/evm/SendAmountFields/LowGasAlertBuyMore";
import TranslatedError from "~/renderer/components/TranslatedError";
import Alert from "~/renderer/components/Alert";

type Props = {
setTransaction: SwapTransactionType["setTransaction"];
mainAccount: AccountLike;
account: AccountLike;
parentAccount: Account;
status: SwapTransactionType["status"];
disableSlowStrategy?: boolean;
Expand All @@ -23,7 +27,7 @@ type Props = {

export default function FeesDrawerLiveApp({
setTransaction,
mainAccount,
account,
parentAccount,
status,
provider,
Expand All @@ -36,15 +40,17 @@ export default function FeesDrawerLiveApp({
const [isOpen, setIsOpen] = useState(true);
const [transaction, setTransactionState] = useState(initialTransaction);
const [transactionStatus, setTransactionStatus] = useState(status);
const mainAccount = getMainAccount(account, parentAccount);

const bridge = getAccountBridge(mainAccount, parentAccount);
const { amount: amountError, gasPrice: gasPriceError } = transactionStatus.errors;

const handleSetTransaction = useCallback(
(transaction: Transaction) => {
const account = mainAccount.type === "TokenAccount" ? parentAccount : mainAccount;
bridge
.prepareTransaction(account, transaction)
.prepareTransaction(mainAccount, transaction)
.then(preparedTransaction =>
bridge.getTransactionStatus(account, preparedTransaction).then(status => {
bridge.getTransactionStatus(mainAccount, preparedTransaction).then(status => {
setTransactionStatus(status);
setTransactionState(preparedTransaction);
setTransaction(preparedTransaction);
Expand All @@ -54,18 +60,17 @@ export default function FeesDrawerLiveApp({
console.error("Error preparing transaction:", error);
});
},
[setTransaction, bridge, mainAccount, parentAccount],
[setTransaction, bridge, mainAccount],
);

const handleUpdateTransaction = useCallback(
(updater: (arg0: Transaction) => Transaction) => {
const account = mainAccount.type === "TokenAccount" ? parentAccount : mainAccount;
setTransactionState(prevTransaction => {
let updatedTransaction = updater(prevTransaction);
bridge
.prepareTransaction(account, updatedTransaction)
.prepareTransaction(mainAccount, updatedTransaction)
.then(preparedTransaction =>
bridge.getTransactionStatus(account, preparedTransaction).then(status => {
bridge.getTransactionStatus(mainAccount, preparedTransaction).then(status => {
setTransactionStatus(status);
setTransaction(preparedTransaction);
updatedTransaction = preparedTransaction;
Expand All @@ -79,7 +84,7 @@ export default function FeesDrawerLiveApp({
return updatedTransaction;
});
},
[setTransaction, bridge, mainAccount, parentAccount],
[setTransaction, bridge, mainAccount],
);

const mapStrategies = useCallback(
Expand Down Expand Up @@ -130,6 +135,19 @@ export default function FeesDrawerLiveApp({
}}
/>
)}
<LowGasAlertBuyMore
account={mainAccount}
handleRequestClose={() => handleRequestClose(false)}
gasPriceError={gasPriceError}
trackingSource={"swap flow"}
/>
{amountError && !gasPriceError && (
<Flex>
<Alert type="warning">
<TranslatedError error={amountError} />
</Alert>
</Flex>
)}
</Box>
<Divider />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ const SwapWebView = ({
FeesDrawerLiveApp,
{
setTransaction,
mainAccount: fromAccount,
account: fromAccount,
parentAccount: fromParentAccount,
status: status,
provider: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ const SwapWebView = ({ manifest, liveAppUnavailable }: SwapWebProps) => {
FeesDrawerLiveApp,
{
setTransaction,
mainAccount: fromAccount,
account: fromAccount,
parentAccount: fromParentAccount,
status: status,
provider: undefined,
Expand Down
Loading