Skip to content
Draft
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
2 changes: 2 additions & 0 deletions apps/extension/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# dependencies
.yalc
yalc.lock
.env
/node_modules
/build
3 changes: 2 additions & 1 deletion apps/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"@dao-xyz/borsh": "^5.1.5",
"@ledgerhq/hw-transport": "^6.31.4",
"@ledgerhq/hw-transport-webusb": "^6.29.4",
"@namada/sdk": "^0.20.7",
"@namada/sdk": "file:.yalc/@namada/sdk",
"@namada/sdk-multicore": "file:.yalc/@namada/sdk-multicore",
"@zondax/ledger-namada": "^2.0.0",
"bignumber.js": "^9.1.1",
"buffer": "^6.0.3",
Expand Down
2 changes: 2 additions & 0 deletions apps/namadillo/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# dependencies
yalc.lock
/.yalc
/node_modules
/.pnp
.pnp.js
Expand Down
2 changes: 1 addition & 1 deletion apps/namadillo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@keplr-wallet/types": "^0.12.136",
"@namada/chain-registry": "^1.3.0",
"@namada/indexer-client": "3.3.2",
"@namada/sdk-multicore": "^0.20.7",
"@namada/sdk-multicore": "file:.yalc/@namada/sdk-multicore",
"@tailwindcss/container-queries": "^0.1.1",
"@tanstack/query-core": "^5.40.0",
"@tanstack/react-query": "^5.40.0",
Expand Down
31 changes: 23 additions & 8 deletions apps/namadillo/src/App/Common/GasFeeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import BigNumber from "bignumber.js";
import clsx from "clsx";
import { TransactionFeeProps } from "hooks/useTransactionFee";
import { useAtomValue } from "jotai";
import { useCallback, useState } from "react";
import { IoClose } from "react-icons/io5";
import { twMerge } from "tailwind-merge";
import { Asset, GasConfig, NamadaAsset } from "types";
Expand Down Expand Up @@ -110,9 +111,12 @@ export const GasFeeModal = ({
onChangeGasToken,
} = feeProps;

const [gasLimit, setGasLimit] = useState<BigNumber>(gasConfig.gasLimit);
const [gasToken, setGasToken] = useState<string>(gasConfig.gasToken);

const sortByNativeToken = useSortByNativeToken();
const buildGasOption = useBuildGasOption({
gasConfig,
gasConfig: { ...gasConfig, gasLimit, gasToken },
gasPriceTable,
chainAssetsMap,
});
Expand Down Expand Up @@ -143,8 +147,19 @@ export const GasFeeModal = ({

const isLoading = isShielded && !shieldedAmount.data;

// We only commit the changes when the modal is closed, this prevents some atoms from triggering too many times
const onCloseCallback = useCallback(() => {
if (typeof gasLimit !== "undefined") {
onChangeGasLimit(gasLimit);
}
if (typeof gasToken !== "undefined") {
onChangeGasToken(gasToken);
}
onClose();
}, [gasLimit, gasToken]);

return (
<Modal onClose={onClose}>
<Modal onClose={onCloseCallback}>
<div
className={twMerge(
"fixed min-w-[550px] top-1/2 left-1/2 -translate-y-1/2 -translate-x-1/2",
Expand All @@ -156,7 +171,7 @@ export const GasFeeModal = ({
"cursor-pointer text-white absolute right-3 top-3 text-xl",
"hover:text-yellow transition-colors"
)}
onClick={onClose}
onClick={onCloseCallback}
>
<IoClose />
</i>
Expand Down Expand Up @@ -188,7 +203,7 @@ export const GasFeeModal = ({
"cursor-auto bg-yellow text-black"
: "cursor-pointer bg-neutral-800 hover:bg-neutral-700"
)}
onClick={() => onChangeGasLimit(BigNumber(item.amount))}
onClick={() => setGasLimit(BigNumber(item.amount))}
>
<div className="font-semibold">{item.label}</div>
{totalInDollars && (
Expand Down Expand Up @@ -240,7 +255,7 @@ export const GasFeeModal = ({
labelProps={{
className: "group-hover/item:text-current",
}}
onChange={(e) => onChangeGasToken(e.target.value)}
onChange={(e) => setGasToken(e.target.value)}
options={
gasPriceTable
?.filter(filterAvailableTokensOnly)
Expand Down Expand Up @@ -322,8 +337,8 @@ export const GasFeeModal = ({
<AmountInput
label="Gas Amount"
className="[&_input]:border-neutral-800"
value={gasConfig.gasLimit}
onChange={(e) => e.target.value && onChangeGasLimit(e.target.value)}
value={gasLimit}
onChange={(e) => e.target.value && setGasLimit(e.target.value)}
/>
</div>

Expand All @@ -335,7 +350,7 @@ export const GasFeeModal = ({
backgroundHoverColor="yellow"
textColor="white"
textHoverColor="black"
onClick={onClose}
onClick={onCloseCallback}
>
Close
</ActionButton>
Expand Down
10 changes: 9 additions & 1 deletion apps/namadillo/src/App/Common/TransactionFeeButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { namadaRegistryChainAssetsMapAtom } from "atoms/integrations";
import BigNumber from "bignumber.js";
import clsx from "clsx";
import { TransactionFeeProps } from "hooks/useTransactionFee";
import { useAtomValue } from "jotai";
import { useMemo, useState } from "react";
Expand All @@ -13,10 +14,12 @@ export const TransactionFeeButton = ({
feeProps,
className,
isShieldedTransfer = false,
disabled = false,
}: {
feeProps: TransactionFeeProps;
className?: string;
isShieldedTransfer?: boolean;
disabled?: boolean;
}): JSX.Element => {
const [modalOpen, setModalOpen] = useState(false);

Expand All @@ -42,9 +45,14 @@ export const TransactionFeeButton = ({
displayAmount={gasDisplayAmount?.totalDisplayAmount || BigNumber(0)}
symbol={gasDisplayAmount?.asset.symbol || ""}
/>
<div className="flex items-center gap-2">
<div
className={clsx("flex items-center gap-2", {
"pointer-events-none opacity-30": disabled,
})}
>
<div className="text-neutral-500 text-xs">Fee Options:</div>
<button
disabled={disabled}
type="button"
className={twMerge(
"flex items-center gap-1",
Expand Down
51 changes: 51 additions & 0 deletions apps/namadillo/src/App/Masp/LedgerAmountInfoAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Alert, Stack } from "@namada/components";
import BigNumber from "bignumber.js";
import { GoCheckCircle } from "react-icons/go";

export type LedgerAmountInfoAlertProps = {
calculating: boolean;
displayWarning: boolean;
amount: BigNumber;
};
export const LedgerAmountInfoAlert = (
props: LedgerAmountInfoAlertProps
): JSX.Element => {
const { calculating, displayWarning, amount } = props;
return (
<>
{calculating && (
<Alert type="warning" className="w-[480px] mx-auto mb-4">
<Stack direction="horizontal" gap={3} className="items-center">
<i
className={
"block w-6 h-6 border-2 border-transparent border-t-yellow rounded-[50%] animate-loadingSpinner"
}
/>
<p>Calculating the maximum amount you can transfer this time... </p>
</Stack>
</Alert>
)}
{!calculating && displayWarning && (
<Alert type="warning" className="w-[480px] mx-auto mb-4">
<p>
Due to the ledger device memory constrains we have to limit the
amount that you can transfer this time to <b>{amount.toString()}</b>
. Once the transaction is successful, you will be able to send
another transfer.
</p>
</Alert>
)}
{!calculating && !displayWarning && (
<Alert
type="success"
className="w-[480px] mx-auto mb-4 text-black bg-success"
>
<Stack direction="horizontal" gap={3} className="items-center">
<GoCheckCircle className="w-6 h-6" />
<p>You can transfer all the tokens</p>
</Stack>
</Alert>
)}
</>
);
};
58 changes: 56 additions & 2 deletions apps/namadillo/src/App/Masp/MaspUnshield.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ import {
} from "App/Transfer/TransferModule";
import { allDefaultAccountsAtom } from "atoms/accounts";
import {
estimateMaxMaspTxAmountLedgerAtom,
lastCompletedShieldedSyncAtom,
namadaShieldedAssetsAtom,
} from "atoms/balance/atoms";
import { chainParametersAtom } from "atoms/chain/atoms";
import { namadaChainRegistryAtom } from "atoms/integrations";
import {
namadaChainRegistryAtom,
namadaRegistryChainAssetsMapAtom,
} from "atoms/integrations";
import { ledgerStatusDataAtom } from "atoms/ledger/atoms";
import { rpcUrlAtom } from "atoms/settings";
import BigNumber from "bignumber.js";
Expand All @@ -25,7 +29,9 @@ import { wallets } from "integrations";
import invariant from "invariant";
import { useAtom, useAtomValue } from "jotai";
import { createTransferDataFromNamada } from "lib/transactions";
import { useState } from "react";
import { useMemo, useState } from "react";
import { getDisplayGasFee } from "utils/gas";
import { LedgerAmountInfoAlert } from "./LedgerAmountInfoAlert";

export const MaspUnshield: React.FC = () => {
const [displayAmount, setDisplayAmount] = useState<BigNumber | undefined>();
Expand Down Expand Up @@ -140,6 +146,43 @@ export const MaspUnshield: React.FC = () => {
}
}
};

const chainAssetsMap = useAtomValue(namadaRegistryChainAssetsMapAtom);
const maxAmount = useMemo(() => {
if (!selectedAsset) {
return BigNumber(0);
}
const { gasToken } = feeProps.gasConfig;
const token = selectedAsset.asset.address;

const displayGas = getDisplayGasFee(
feeProps.gasConfig,
chainAssetsMap.data || {}
);
const amount =
token === gasToken ?
selectedAsset.amount.minus(displayGas.totalDisplayAmount)
: selectedAsset.amount;

return amount;
}, [selectedAsset?.asset.address]);

const [maxMaspTxAmountQuery, maxMaspTxAmountQueryStop] = useAtom(
estimateMaxMaspTxAmountLedgerAtom({
source: account?.pseudoExtendedKey,
target: destinationAddress,
token: selectedAsset?.asset.address,
feeToken: feeProps.gasConfig.gasToken,
feeAmount: feeProps.gasConfig.gasPriceInMinDenom.times(
feeProps.gasConfig.gasLimit
),
})
);
const maxMaspTxAmount = maxMaspTxAmountQuery?.data;
// We stop estimations when transfer is in progress to not use the workers, this is useful especially when query
// runs on window focus or in interval
maxMaspTxAmountQueryStop(isPerformingTransfer);

// We stop the ledger status check when the transfer is in progress
setLedgerStatusStop(isPerformingTransfer);

Expand All @@ -151,12 +194,22 @@ export const MaspUnshield: React.FC = () => {
isDestinationShielded={false}
/>
</header>
{maxMaspTxAmountQuery && (
<LedgerAmountInfoAlert
calculating={maxMaspTxAmountQuery.isPending}
displayWarning={Boolean(
maxMaspTxAmount && maxMaspTxAmount.lt(maxAmount)
)}
amount={maxMaspTxAmount || BigNumber(0)}
/>
)}
<TransferModule
source={{
isLoadingAssets: isLoadingAssets,
availableAssets,
selectedAssetAddress,
availableAmount: selectedAsset?.amount,
maxAmount: maxMaspTxAmount,
chain,
availableWallets: [wallets.namada],
wallet: wallets.namada,
Expand Down Expand Up @@ -186,6 +239,7 @@ export const MaspUnshield: React.FC = () => {
buttonTextErrors={{
NoAmount: "Define an amount to unshield",
}}
disabled={maxMaspTxAmountQuery?.isPending}
/>
{requiresNewSync && <MaspSyncCover longSync={lastSync === undefined} />}
</Panel>
Expand Down
Loading