diff --git a/packages/extension/src/providers/ethereum/ui/send-transaction/components/send-alert.vue b/packages/extension/src/providers/ethereum/ui/send-transaction/components/send-alert.vue
new file mode 100644
index 000000000..046f53424
--- /dev/null
+++ b/packages/extension/src/providers/ethereum/ui/send-transaction/components/send-alert.vue
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
diff --git a/packages/extension/src/providers/ethereum/ui/send-transaction/index.vue b/packages/extension/src/providers/ethereum/ui/send-transaction/index.vue
index 5d638b745..a00efafc0 100644
--- a/packages/extension/src/providers/ethereum/ui/send-transaction/index.vue
+++ b/packages/extension/src/providers/ethereum/ui/send-transaction/index.vue
@@ -103,18 +103,7 @@
@gas-type-changed="selectFee"
/>
-
+
@@ -143,7 +132,7 @@ import SendContactsList from '@/providers/common/ui/send-transaction/send-contac
import AssetsSelectList from '@action/views/assets-select-list/index.vue';
import NftSelectList from '@/providers/common/ui/send-transaction/nft-select-list/index.vue';
import SendTokenSelect from './components/send-token-select.vue';
-import SendAlert from '@/providers/common/ui/send-transaction/send-alert.vue';
+import SendAlert from './components/send-alert.vue';
import SendNftSelect from '@/providers/common/ui/send-transaction/send-nft-select.vue';
import SendInputAmount from '@/providers/common/ui/send-transaction/send-input-amount.vue';
import SendFeeSelect from '@/providers/common/ui/send-transaction/send-fee-select.vue';
@@ -169,6 +158,7 @@ import erc721 from '../../libs/abi/erc721';
import erc1155 from '../../libs/abi/erc1155';
import { SendTransactionDataType, VerifyTransactionParams } from '../types';
import {
+ formatFiatValue,
formatFloatingPointValue,
isNumericPositive,
} from '@/libs/utils/number-formatter';
@@ -217,11 +207,19 @@ const accountAssets = ref([]);
const selectedAsset = ref>(loadingAsset);
const amount = ref('');
const isEstimateValid = ref(true);
+const hasValidDecimals = computed(() => {
+ return isValidDecimals(sendAmount.value, selectedAsset.value.decimals!);
+});
+const hasPositiveSendAmount = computed(() => {
+ return isNumericPositive(sendAmount.value);
+});
const hasEnoughBalance = computed(() => {
- if (!isValidDecimals(sendAmount.value, selectedAsset.value.decimals!)) {
+ if (!hasValidDecimals.value) {
+ return false;
+ }
+ if (!hasPositiveSendAmount.value) {
return false;
}
-
// check if valid sendAmount.value
if (!isNumericPositive(sendAmount.value)) {
return false;
@@ -341,7 +339,11 @@ const Tx = computed(() => {
return tx;
});
-const nativeBalanceAfterTransaction = computed(() => {
+/**
+ * Native balance after the transaction in the base unit of the
+ * native currency (eg in WETH, Lamports, Satoshis, ...)
+ */
+const nativeBalanceAfterTransactionInBaseUnits = computed(() => {
if (
isSendToken.value &&
nativeBalance.value &&
@@ -390,6 +392,71 @@ const nativeBalanceAfterTransaction = computed(() => {
return toBN(0);
});
+/**
+ * Native balance after the transaction in the human unit of the
+ * native currency (eg in ETH, SOL, BTC, ...)
+ */
+const nativeBalanceAfterTransactionInHumanUnits = computed(() => {
+ return fromBase(
+ nativeBalanceAfterTransactionInBaseUnits.value.abs().toString(),
+ props.network.decimals,
+ );
+});
+
+const nativeCurrencyUsdPrice = computed(() => {
+ return accountAssets.value[0]?.price || '0';
+});
+
+const balanceAfterInUsd = computed(() => {
+ return new BigNumber(
+ nativeBalanceAfterTransactionInHumanUnits.value.toString(),
+ )
+ .times(nativeCurrencyUsdPrice.value ?? '0')
+ .toFixed();
+});
+
+const errorMsg = computed(() => {
+ if (!hasValidDecimals.value) {
+ return `Too many decimals.`;
+ }
+
+ if (!hasPositiveSendAmount.value) {
+ return `Invalid amount.`;
+ }
+
+ if (
+ !hasEnoughBalance.value &&
+ nativeBalanceAfterTransactionInBaseUnits.value.isNeg()
+ ) {
+ return `Not enough funds. You are
+ ~${formatFloatingPointValue(nativeBalanceAfterTransactionInHumanUnits.value).value}
+ ${props.network.currencyName} ($ ${
+ formatFiatValue(balanceAfterInUsd.value).value
+ }) short.`;
+ }
+
+ if (!props.network.isAddress(addressTo.value) && addressTo.value !== '') {
+ return `Invalid to address.`;
+ }
+
+ if (
+ isSendToken.value &&
+ !isValidDecimals(sendAmount.value, selectedAsset.value.decimals!)
+ ) {
+ return `Invalid decimals for ${selectedAsset.value.symbol}.`;
+ }
+
+ if (!isSendToken.value && !selectedNft.value.id) {
+ return `Invalid NFT selected.`;
+ }
+
+ if (new BigNumber(sendAmount.value).gt(assetMaxValue.value)) {
+ return `Amount exceeds maximum value.`;
+ }
+
+ return '';
+});
+
const setTransactionFees = (tx: Transaction) => {
return tx
.getGasCosts()
@@ -479,7 +546,7 @@ const sendButtonTitle = computed(() => {
const isValidSend = computed(() => {
if (!isInputsValid.value) return false;
- if (nativeBalanceAfterTransaction.value.isNeg()) return false;
+ if (nativeBalanceAfterTransactionInBaseUnits.value.isNeg()) return false;
if (!isEstimateValid.value) return false;
return true;
});
diff --git a/packages/extension/src/providers/solana/ui/send-transaction/index.vue b/packages/extension/src/providers/solana/ui/send-transaction/index.vue
index 1f59aeda9..38c6a9594 100644
--- a/packages/extension/src/providers/solana/ui/send-transaction/index.vue
+++ b/packages/extension/src/providers/solana/ui/send-transaction/index.vue
@@ -140,6 +140,7 @@ import { VerifyTransactionParams, SendTransactionDataType } from '../types';
import {
formatFloatingPointValue,
formatFiatValue,
+ isNumericPositive,
} from '@/libs/utils/number-formatter';
import { routes as RouterNames } from '@/ui/action/router';
import getUiPath from '@/libs/utils/get-ui-path';
@@ -172,6 +173,7 @@ import {
import getPriorityFees from '../libs/get-priority-fees';
import bs58 from 'bs58';
import SolanaAPI from '@/providers/solana/libs/api';
+import { ComputedRefSymbol } from '@vue/reactivity';
const props = defineProps({
network: {
@@ -211,8 +213,17 @@ const amount = ref('');
const isEstimateValid = ref(true);
const storageFee = ref(0);
const SolTx = ref();
-const hasEnoughBalance = computed(() => {
- if (!isValidDecimals(sendAmount.value, selectedAsset.value.decimals!)) {
+const hasValidDecimals = computed((): boolean => {
+ return isValidDecimals(sendAmount.value, selectedAsset.value.decimals!);
+});
+const hasPositiveSendAmount = computed(() => {
+ return isNumericPositive(sendAmount.value);
+});
+const hasEnoughBalance = computed((): boolean => {
+ if (!hasValidDecimals.value) {
+ return false;
+ }
+ if (!hasPositiveSendAmount.value) {
return false;
}
return toBN(selectedAsset.value.balance ?? '0').gte(
@@ -276,7 +287,11 @@ const TxInfo = computed(() => {
};
});
-const nativeBalanceAfterTransaction = computed(() => {
+/**
+ * Native balance after the transaction in the base unit of the
+ * native currency (eg in WETH, Lamports, Satoshis, ...)
+ */
+const nativeBalanceAfterTransactionInBaseUnits = computed(() => {
if (
isSendToken.value &&
nativeBalance.value &&
@@ -320,47 +335,71 @@ const nativeBalanceAfterTransaction = computed(() => {
return toBN(0);
});
-const nativeValue = computed(() => {
+/**
+ * Native balance after the transaction in the human unit of the
+ * native currency (eg in ETH, SOL, BTC, ...)
+ */
+const nativeBalanceAfterTransactionInHumanUnits = computed(() => {
return fromBase(
- nativeBalanceAfterTransaction.value.toString(),
+ nativeBalanceAfterTransactionInBaseUnits.value.abs().toString(),
props.network.decimals,
);
});
-const nativePrice = computed(() => {
+const nativeCurrencyUsdPrice = computed(() => {
return accountAssets.value[0]?.price || '0';
});
-const priceDifference = computed(() => {
- return new BigNumber(nativeValue.value)
- .times(nativePrice.value ?? '0')
+const balanceAfterInUsd = computed(() => {
+ return new BigNumber(
+ nativeBalanceAfterTransactionInHumanUnits.value.toString(),
+ )
+ .times(nativeCurrencyUsdPrice.value ?? '0')
.toFixed();
});
const errorMsg = computed(() => {
- if (hasEnoughBalance.value && nativeBalanceAfterTransaction.value.isNeg()) {
+ if (!hasValidDecimals.value) {
+ return `Too many decimals.`;
+ }
+
+ if (!hasPositiveSendAmount.value) {
+ return `Invalid amount.`;
+ }
+
+ if (
+ !hasEnoughBalance.value &&
+ nativeBalanceAfterTransactionInBaseUnits.value.isNeg()
+ ) {
return `Not enough funds. You are
- ~${formatFloatingPointValue(nativeValue.value).value}
+ ~${formatFloatingPointValue(nativeBalanceAfterTransactionInHumanUnits.value).value}
${props.network.currencyName} ($ ${
- formatFiatValue(priceDifference.value).value
+ formatFiatValue(balanceAfterInUsd.value).value
}) short.`;
}
+
if (
!props.network.isAddress(getAddress(addressTo.value)) &&
addressTo.value !== ''
- )
+ ) {
return `Invalid to address.`;
+ }
+
if (
isSendToken.value &&
!isValidDecimals(sendAmount.value, selectedAsset.value.decimals!)
) {
return `Invalid decimals for ${selectedAsset.value.symbol}.`;
}
+
if (!isSendToken.value && !selectedNft.value.id) {
return `Invalid NFT selected.`;
}
- if (new BigNumber(sendAmount.value).gt(assetMaxValue.value))
+
+ if (new BigNumber(sendAmount.value).gt(assetMaxValue.value)) {
return `Amount exceeds maximum value.`;
+ }
+
return '';
});
@@ -418,7 +457,7 @@ const sendButtonTitle = computed(() => {
const isValidSend = computed(() => {
if (!isInputsValid.value) return false;
- if (nativeBalanceAfterTransaction.value.isNeg()) return false;
+ if (nativeBalanceAfterTransactionInBaseUnits.value.isNeg()) return false;
if (!isEstimateValid.value) return false;
if (gasCostValues.value.ECONOMY.nativeValue === '0') return false;
return true;
diff --git a/packages/extension/src/ui/action/views/swap/views/swap-best-offer/components/swap-best-offer-block/components/best-offer-warning.vue b/packages/extension/src/ui/action/views/swap/views/swap-best-offer/components/swap-best-offer-block/components/best-offer-warning.vue
index 2f1597081..890f48586 100644
--- a/packages/extension/src/ui/action/views/swap/views/swap-best-offer/components/swap-best-offer-block/components/best-offer-warning.vue
+++ b/packages/extension/src/ui/action/views/swap/views/swap-best-offer/components/swap-best-offer-block/components/best-offer-warning.vue
@@ -15,6 +15,8 @@