diff --git a/src/i18n/en-US/index.ts b/src/i18n/en-US/index.ts index 32ebbe561..e74aa226a 100644 --- a/src/i18n/en-US/index.ts +++ b/src/i18n/en-US/index.ts @@ -443,7 +443,7 @@ export default { 'The amount of token to be staking must be greater than {amount} {symbol}', allFundsWillBeTransferred: 'All funds will be transferred because the min. staking amount is {minStakingAmount} {symbol}', - invalidBalance: 'Insufficient transferrable balance to complete the transaction', + invalidBalance: 'You do not have enough tokens to pay the transaction fee', warningLeaveMinAmount: 'Account must hold amount greater than {amount}{symbol} in transferrable after you stake.', }, diff --git a/src/i18n/fr/index.ts b/src/i18n/fr/index.ts index 25fd4b0f5..b699f5f80 100644 --- a/src/i18n/fr/index.ts +++ b/src/i18n/fr/index.ts @@ -443,7 +443,7 @@ export default { 'Le montant de jeton à mettre en staking doit être supérieur à {amount} {symbol}', allFundsWillBeTransferred: 'Tous les fonds seront transférés car le montant minimum est de {minStakingAmount} {symbol}', - invalidBalance: 'Solde transférable insuffisant pour finaliser la transaction', + invalidBalance: "Vous n'avez pas assez de jetons pour payer les frais de transaction", warningLeaveMinAmount: 'Le compte doit contenir un montant supérieur à {amount}{symbol} transférable lorsque vous misez.', }, diff --git a/src/i18n/pt/index.ts b/src/i18n/pt/index.ts index f1ecbada7..8743a7801 100644 --- a/src/i18n/pt/index.ts +++ b/src/i18n/pt/index.ts @@ -429,7 +429,7 @@ export default { notEnoughMinAmount: 'A quantidade de token em stake deve ser maior que {amount} {symbol}', allFundsWillBeTransferred: 'Todos os fundos serão transferidos porque o valor min. do stake é {minStakingAmount} {symbol}', - invalidBalance: 'Saldo transferível insuficiente para concluir a transação', + invalidBalance: 'Você não tem tokens suficientes para pagar a taxa de transação', warningLeaveMinAmount: 'A conta deve conter mais de {amount}{symbol} em valor transferível quando você faz stake.', }, diff --git a/src/modules/toast/index.ts b/src/modules/toast/index.ts index ee856e003..492389736 100644 --- a/src/modules/toast/index.ts +++ b/src/modules/toast/index.ts @@ -4,4 +4,7 @@ export enum AlertMsg { ERROR = 'Transaction failed', ERROR_DUPLICATED_TX = 'Transaction failed due to duplicate transactions on PolkaSafe; please approve or reject them before creating a new transaction', COMPLETED_HASH = 'Completed at transaction hash', + MINIMUM_BALANCE = 'You do not have enough tokens to pay the transaction fee', } + +export const REQUIRED_MINIMUM_BALANCE: number = 0.05; diff --git a/src/v2/services/implementations/AssetsService.ts b/src/v2/services/implementations/AssetsService.ts index d79cec35a..0e096bf64 100644 --- a/src/v2/services/implementations/AssetsService.ts +++ b/src/v2/services/implementations/AssetsService.ts @@ -3,6 +3,7 @@ import { getEvmProvider } from 'src/hooks/helper/wallet'; import { IEventAggregator } from 'src/v2/messaging'; import { IAssetsRepository } from 'src/v2/repositories/IAssetsRepository'; import { IAssetsService, IWalletService } from 'src/v2/services'; +import { AlertMsg, REQUIRED_MINIMUM_BALANCE } from 'src/modules/toast/index'; import { ParamAssetTransfer, ParamEvmTransfer, @@ -10,6 +11,7 @@ import { } from 'src/v2/services/IAssetsService'; import { Symbols } from 'src/v2/symbols'; import Web3 from 'web3'; +import { ethers } from 'ethers'; @injectable() export class AssetsService implements IAssetsService { @@ -26,33 +28,51 @@ export class AssetsService implements IAssetsService { } public async transferNativeAsset(param: ParamAssetTransfer): Promise { - const transaction = await this.AssetsRepository.getNativeTransferCall(param); - const hash = await this.wallet.signAndSend({ - extrinsic: transaction, - senderAddress: param.senderAddress, - successMessage: param.successMessage, - }); - param.finalizedCallback(String(hash)); + const useableBalance = await this.AssetsRepository.getNativeBalance(param.senderAddress); + const isBalanceEnough = + Number(ethers.utils.formatEther(useableBalance)) - + Number(ethers.utils.formatEther(param.amount)) > + REQUIRED_MINIMUM_BALANCE; + + if (isBalanceEnough) { + const transaction = await this.AssetsRepository.getNativeTransferCall(param); + const hash = await this.wallet.signAndSend({ + extrinsic: transaction, + senderAddress: param.senderAddress, + successMessage: param.successMessage, + }); + param.finalizedCallback(String(hash)); + } else { + throw new Error(AlertMsg.MINIMUM_BALANCE); + } } public async transferEvmAsset(param: ParamEvmTransfer): Promise { const provider = getEvmProvider(this.currentWallet as any); const web3 = new Web3(provider as any); - const rawTx = await this.AssetsRepository.getEvmTransferData({ - param, - web3, - }); - const isErc20 = !!rawTx.data; + const balWei = await web3.eth.getBalance(param.senderAddress); + const useableBalance = Number(ethers.utils.formatEther(balWei)); + const isBalanceEnough = useableBalance - Number(param.amount) > REQUIRED_MINIMUM_BALANCE; + if (isBalanceEnough) { + const rawTx = await this.AssetsRepository.getEvmTransferData({ + param, + web3, + }); - const transactionHash = await this.wallet.sendEvmTransaction({ - from: param.senderAddress, - to: isErc20 ? param.contractAddress : param.toAddress, - value: isErc20 ? '0x0' : String(rawTx.value), - data: isErc20 ? rawTx.data : null, - }); + const isErc20 = !!rawTx.data; + + const transactionHash = await this.wallet.sendEvmTransaction({ + from: param.senderAddress, + to: isErc20 ? param.contractAddress : param.toAddress, + value: isErc20 ? '0x0' : String(rawTx.value), + data: isErc20 ? rawTx.data : null, + }); - param.finalizedCallback(transactionHash); + param.finalizedCallback(transactionHash); + } else { + throw Error(AlertMsg.MINIMUM_BALANCE); + } } public async evmWithdraw({ amount, senderAddress }: ParamEvmWithdraw): Promise { diff --git a/src/v2/services/implementations/PolkadotWalletService.ts b/src/v2/services/implementations/PolkadotWalletService.ts index 78097facb..82ee84f75 100644 --- a/src/v2/services/implementations/PolkadotWalletService.ts +++ b/src/v2/services/implementations/PolkadotWalletService.ts @@ -8,7 +8,7 @@ import { inject, injectable } from 'inversify'; import { LOCAL_STORAGE } from 'src/config/localStorage'; import { isMobileDevice } from 'src/hooks/helper/wallet'; import { getSubscanExtrinsic, polkasafeUrl } from 'src/links'; -import { AlertMsg } from 'src/modules/toast/index'; +import { AlertMsg, REQUIRED_MINIMUM_BALANCE } from 'src/modules/toast/index'; import { Guard, wait } from 'src/v2/common'; import { BusyMessage, ExtrinsicStatusMessage, IEventAggregator } from 'src/v2/messaging'; import { Account } from 'src/v2/models'; @@ -70,6 +70,16 @@ export class PolkadotWalletService extends WalletService implements IWalletServi return new Promise(async (resolve, reject) => { isDetectExtensionsAction && this.detectExtensionsAction(true); + const useableBalance = await this.assetsRepository.getNativeBalance(senderAddress); + const isBalanceEnough = + Number(ethers.utils.formatEther(useableBalance)) > REQUIRED_MINIMUM_BALANCE; + if (!isBalanceEnough) { + this.eventAggregator.publish( + new ExtrinsicStatusMessage({ success: false, message: AlertMsg.MINIMUM_BALANCE }) + ); + throw new Error(AlertMsg.MINIMUM_BALANCE); + } + await this.checkExtension(); let tip = transactionTip?.toString(); if (!tip) {