-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
feat(bridge-ui-v2): Fixed input validations and catching additional errors #14331
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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'; | ||
|
@@ -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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this fixing a problem? We're gonna validate these two, we start assuming there is no issue and then validate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, it helps with the flickering of the buttons. In the future we could introduce a loading or disabled status |
||
|
||
const to = $recipientAddress || $account?.address; | ||
const walletClient = await getConnectedWallet(); | ||
|
||
// We need all these guys to validate | ||
if ( | ||
|
@@ -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({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need to do this here?, we already get the error when running the estimation, don't we?, is this not redundant? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed in the call, the gas estimation does not throw an error, so we need to call it. |
||
amount: $enteredAmount, | ||
tokenAddress, | ||
ownerAddress: walletClient.account.address, | ||
spenderAddress, | ||
} as RequireAllowanceArgs); | ||
|
||
if ($insufficientAllowance) return; | ||
|
||
try { | ||
await checkBalanceToBridge({ | ||
|
@@ -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> |
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'; | ||
|
@@ -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'; | ||
|
@@ -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')); | ||
|
@@ -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 | ||
|
@@ -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.': | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not quite understand why this is needed? denying tx signature is handled in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed, we can move this logic to the ERC20Bridge but for some reason the wrong error is thrown and we need to catch it |
||
//Todo: so we catch it by string comparison below, suboptimal | ||
warningToast($t('bridge.errors.rejected')); | ||
break; | ||
default: | ||
errorToast($t('bridge.errors.unknown_error')); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we want to clear on mount? If the reason is to clear the state, before we actually wanted to leave the amount on purpose when switching pages
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not persisting (visibly) right now. We either clear it here or we make sure it is also displayed.