Skip to content

Commit

Permalink
feat(bridge-ui-v2): Fixed input validations and catching additional e…
Browse files Browse the repository at this point in the history
…rrors (#14331)
  • Loading branch information
KorbinianK authored Aug 2, 2023
1 parent 9661ddc commit 4a78b6b
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 29 deletions.
62 changes: 46 additions & 16 deletions packages/bridge-ui-v2/src/components/Bridge/Amount.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
<script lang="ts">
import type { FetchBalanceResult } from '@wagmi/core';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
import { formatUnits, parseUnits } from 'viem';
import { FlatAlert } from '$components/Alert';
import { InputBox } from '$components/InputBox';
import { LoadingText } from '$components/LoadingText';
import { warningToast } from '$components/NotificationToast';
import { checkBalanceToBridge, getMaxAmountToBridge } from '$libs/bridge';
import { bridges, checkBalanceToBridge, getMaxAmountToBridge, type RequireAllowanceArgs } from '$libs/bridge';
import type { ERC20Bridge } from '$libs/bridge/ERC20Bridge';
import { chainContractsMap } from '$libs/chain';
import { InsufficientAllowanceError, InsufficientBalanceError, RevertedWithFailedError } from '$libs/error';
import { getBalance as getTokenBalance } from '$libs/token';
import { getAddress,getBalance as getTokenBalance } from '$libs/token';
import { debounce } from '$libs/util/debounce';
import { getConnectedWallet } from '$libs/util/getConnectedWallet';
import { truncateString } from '$libs/util/truncateString';
import { uid } from '$libs/util/uid';
import { account } from '$stores/account';
Expand All @@ -33,17 +37,19 @@
let inputBox: InputBox;
let computingMaxAmount = false;
onMount(() => {
clearAmount();
});
// Public API
export function clearAmount() {
inputBox.clear();
$enteredAmount = BigInt(0);
}
export async function validateAmount(token = $selectedToken, fee = $processingFee) {
$insufficientBalance = false;
$insufficientAllowance = false;
const to = $recipientAddress || $account?.address;
const walletClient = await getConnectedWallet();
// We need all these guys to validate
if (
Expand All @@ -53,8 +59,38 @@
!$destNetwork ||
!$tokenBalance ||
$enteredAmount === BigInt(0) // no need to check if the amount is 0
)
) {
$insufficientBalance = false;
return;
}
if ($enteredAmount > $tokenBalance.value) {
$insufficientBalance = true;
// no need to check any further if the amount is greater than the balance
return;
}
$insufficientBalance = false;
const erc20Bridge = bridges.ERC20 as ERC20Bridge;
const spenderAddress = chainContractsMap[$network.id].tokenVaultAddress;
const tokenAddress = await getAddress({
token,
srcChainId: $network.id,
destChainId: $destNetwork.id,
});
if (!tokenAddress) return;
// Check for allowance
$insufficientAllowance = await erc20Bridge.requireAllowance({
amount: $enteredAmount,
tokenAddress,
ownerAddress: walletClient.account.address,
spenderAddress,
} as RequireAllowanceArgs);
if ($insufficientAllowance) return;
try {
await checkBalanceToBridge({
Expand Down Expand Up @@ -208,16 +244,10 @@
{$t('amount_input.button.max')}
</button>
</div>

{#if $insufficientBalance}
<FlatAlert type="error" message={$t('amount_input.error.insufficient_balance')} class="absolute bottom-[-26px]" />
{/if}

{#if $insufficientAllowance}
<FlatAlert
type="warning"
message={$t('amount_input.error.insufficient_allowance')}
class="absolute bottom-[-26px]" />
{#if $insufficientBalance && $enteredAmount > 0}
<FlatAlert type="error" message={$t('error.insufficient_balance')} class="absolute bottom-[-26px]" />
{:else if $insufficientAllowance && $enteredAmount > 0}
<FlatAlert type="warning" message={$t('error.insufficient_allowance')} class="absolute bottom-[-26px]" />
{/if}
</div>
</div>
25 changes: 21 additions & 4 deletions packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { t } from 'svelte-i18n';
import { UserRejectedRequestError } from 'viem';
import { TransactionExecutionError, UserRejectedRequestError } from 'viem';
import { Card } from '$components/Card';
import { ChainSelector } from '$components/ChainSelector';
Expand All @@ -13,7 +13,13 @@
import { type BridgeArgs, bridges, type ERC20BridgeArgs, type ETHBridgeArgs } from '$libs/bridge';
import type { ERC20Bridge } from '$libs/bridge/ERC20Bridge';
import { chainContractsMap, chains } from '$libs/chain';
import { ApproveError, NoAllowanceRequiredError, SendERC20Error, SendMessageError } from '$libs/error';
import {
ApproveError,
InsufficientAllowanceError,
NoAllowanceRequiredError,
SendERC20Error,
SendMessageError,
} from '$libs/error';
import { ETHToken, getAddress, isDeployedCrossChain, tokens, TokenType } from '$libs/token';
import { getConnectedWallet } from '$libs/util/getConnectedWallet';
import { type Account, account } from '$stores/account';
Expand Down Expand Up @@ -107,6 +113,9 @@
case err instanceof NoAllowanceRequiredError:
errorToast($t('bridge.errors.no_allowance_required'));
break;
case err instanceof InsufficientAllowanceError:
errorToast($t('bridge.errors.insufficient_allowance'));
break;
case err instanceof ApproveError:
// TODO: see contract for all possible errors
errorToast($t('bridge.errors.approve_error'));
Expand Down Expand Up @@ -210,8 +219,8 @@
console.error(err);
switch (true) {
case err instanceof UserRejectedRequestError:
warningToast($t('bridge.errors.rejected'));
case err instanceof InsufficientAllowanceError:
errorToast($t('bridge.errors.insufficient_allowance'));
break;
case err instanceof SendMessageError:
// TODO: see contract for all possible errors
Expand All @@ -221,6 +230,14 @@
// TODO: see contract for all possible errors
errorToast($t('bridge.errors.send_erc20_error'));
break;
case err instanceof UserRejectedRequestError:
// Todo: viem does not seem to detect UserRejectError
warningToast($t('bridge.errors.rejected'));
break;
case err instanceof TransactionExecutionError && err.shortMessage === 'User rejected the request.':
//Todo: so we catch it by string comparison below, suboptimal
warningToast($t('bridge.errors.rejected'));
break;
default:
errorToast($t('bridge.errors.unknown_error'));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { switchNetwork } from '@wagmi/core';
import { t } from 'svelte-i18n';
import { UserRejectedRequestError } from 'viem';
import { SwitchChainError, UserRejectedRequestError } from 'viem';
import { Icon } from '$components/Icon';
import { warningToast } from '$components/NotificationToast';
Expand All @@ -15,8 +15,9 @@
await switchNetwork({ chainId: $destNetwork.id });
} catch (err) {
console.error(err);
if (err instanceof UserRejectedRequestError) {
if (err instanceof SwitchChainError) {
warningToast($t('messages.network.pending'));
} else if (err instanceof UserRejectedRequestError) {
warningToast($t('messages.network.rejected'));
}
}
Expand Down
6 changes: 4 additions & 2 deletions packages/bridge-ui-v2/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"send_message_error": "Failed to send message",
"approve_error": "Failed to approve token",
"rejected": "Request to bridge rejected.",
"no_allowance_required": "You need to add allowance to bridge this token.",
"no_allowance_required": "You already have enough allowance.",
"insufficient_allowance": "You need to increase your allowance in order to be able to bridge.",
"unknown_error": "An error occured"
},
"button": {
Expand Down Expand Up @@ -174,7 +175,8 @@
},
"network": {
"switching": "Switching network",
"rejected": "Request to switch chain rejected."
"rejected": "Request to switch chain rejected.",
"pending": "A network switch is still pending, open your wallet to check the status."
}
},
"common": {
Expand Down
15 changes: 11 additions & 4 deletions packages/bridge-ui-v2/src/libs/bridge/checkBalanceToBridge.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getPublicClient } from '@wagmi/core';
import { type Address, zeroAddress } from 'viem';

import { chainContractsMap } from '$libs/chain';
Expand Down Expand Up @@ -61,10 +62,16 @@ export async function checkBalanceToBridge({
throw new RevertedWithFailedError('BLL token doing its thing', { cause: err });
}
}
if (estimatedCost > balance - amount) {
throw new InsufficientBalanceError('you do not have enough balance to bridge');
}
} else {
const { tokenVaultAddress } = chainContractsMap[srcChainId];
const tokenAddress = await getAddress({ token, srcChainId, destChainId });

// since we are briding a token, we need the ETH balance of the wallet
balance = await getPublicClient().getBalance(wallet.account);

if (!tokenAddress || tokenAddress === zeroAddress) return false;

const isTokenAlreadyDeployed = await isDeployedCrossChain({
Expand All @@ -88,9 +95,9 @@ export async function checkBalanceToBridge({
throw new InsufficientAllowanceError(`insufficient allowance for the amount ${amount}`, { cause: err });
}
}
}

if (estimatedCost > balance - amount) {
throw new InsufficientBalanceError('you do not have enough balance to bridge');
// no need to deduct the amount we want to bridge from the balance as we pay in ETH
if (estimatedCost > balance) {
throw new InsufficientBalanceError('you do not have enough balance to bridge');
}
}
}

0 comments on commit 4a78b6b

Please sign in to comment.