Skip to content
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): polishing #17460

Merged
merged 23 commits into from
Jun 6, 2024
Merged
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
18 changes: 9 additions & 9 deletions packages/bridge-ui/src/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
export const gasLimitConfig = {
GAS_RESERVE: 650_000, // based on Bridge.sol
ethGasLimit: BigInt(100_000),
erc20NotDeployedGasLimit: BigInt(650_000),
erc20DeployedGasLimit: BigInt(200_000),
erc721NotDeployedGasLimit: BigInt(2_400_000),
erc721DeployedGasLimit: BigInt(1_100_000),
erc1155NotDeployedGasLimit: BigInt(2_600_000),
erc1155DeployedGasLimit: BigInt(1_100_000),
ethGasLimit: 100_000,
erc20NotDeployedGasLimit: 650_000,
erc20DeployedGasLimit: 200_000,
erc721NotDeployedGasLimit: 2_400_000,
erc721DeployedGasLimit: 1_100_000,
erc1155NotDeployedGasLimit: 2_600_000,
erc1155DeployedGasLimit: 1_100_000,
};

export const processingFeeComponent = {
Expand Down Expand Up @@ -46,8 +46,8 @@ export const apiService = {
};

export const ipfsConfig = {
gatewayTimeout: 200,
overallTimeout: 5000,
gatewayTimeout: 1_000,
overallTimeout: 5_000,
};

export const moralisApiConfig = {
Expand Down
2 changes: 1 addition & 1 deletion packages/bridge-ui/src/components/Alert/Alert.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
iconFillClass: 'fill-warning-content',
},
error: {
alertClass: 'alert-danger',
alertClass: 'alert-error',
iconType: 'x-close-circle',
iconFillClass: 'fill-error-content',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
let stepDescription: string;

let hasEnoughEth: boolean = false;
let hasEnoughFundsToContinue: boolean = false;
let exceedsQuota: boolean = false;
let bridgingStatus: BridgingStatus;
let needsManualReviewConfirmation: boolean;

Expand Down Expand Up @@ -50,14 +52,15 @@
<div class="space-y-[30px] mt-[30px]">
{#if activeStep === BridgeSteps.IMPORT}
<!-- IMPORT STEP -->
<ImportStep bind:hasEnoughEth />
<ImportStep bind:hasEnoughEth bind:exceedsQuota />
{:else if activeStep === BridgeSteps.REVIEW}
<!-- REVIEW STEP -->
<ReviewStep
on:editTransactionDetails={handleTransactionDetailsClick}
on:goBack={handleBackClick}
bind:needsManualReviewConfirmation
bind:hasEnoughEth />
bind:hasEnoughEth
bind:hasEnoughFundsToContinue />
{:else if activeStep === BridgeSteps.RECIPIENT}
<!-- RECIPIENT STEP -->
<RecipientStep bind:this={recipientStepComponent} bind:hasEnoughEth bind:needsManualRecipientConfirmation />
Expand All @@ -68,6 +71,8 @@
<!-- NAVIGATION -->
<StepNavigation
bind:activeStep
bind:exceedsQuota
bind:hasEnoughFundsToContinue
{bridgingStatus}
bind:needsManualReviewConfirmation
bind:needsManualRecipientConfirmation />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
let validInput = false;

export let hasEnoughEth: boolean = false;
export let exceedsQuota: boolean = false;

const reset = () => {
$recipientAddress = null;
Expand All @@ -25,4 +26,4 @@

<ChainSelector type={ChainSelectorType.COMBINED} />

<TokenInput bind:validInput bind:hasEnoughEth />
<TokenInput bind:validInput bind:hasEnoughEth bind:exceedsQuota />
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
import { type Address, zeroAddress } from 'viem';
import { formatUnits, parseUnits } from 'viem/utils';

import { FlatAlert } from '$components/Alert';
Expand All @@ -22,10 +23,12 @@
import { InputBox } from '$components/InputBox';
import { LoadingText } from '$components/LoadingText';
import OnAccount from '$components/OnAccount/OnAccount.svelte';
import { OnNetwork } from '$components/OnNetwork';
import { TokenDropdown } from '$components/TokenDropdown';
import { getMaxAmountToBridge } from '$libs/bridge';
import { fetchBalance, tokens } from '$libs/token';
import { ContractType, getMaxAmountToBridge } from '$libs/bridge';
import { exceedsQuota as checkQuota } from '$libs/bridge/checkBridgeQuota';
import { getContractAddressByType } from '$libs/bridge/getContractAddressByType';
import { ETHToken, fetchBalance, tokens } from '$libs/token';
import { getTokenAddresses } from '$libs/token/getTokenAddresses';
import { isToken } from '$libs/token/isToken';
import { refreshUserBalance, renderBalance } from '$libs/util/balance';
import { debounce } from '$libs/util/debounce';
Expand All @@ -35,11 +38,13 @@
import { account } from '$stores/account';
import { ethBalance } from '$stores/balance';
import { connectedSourceChain } from '$stores/network';
import type { TokenInfo } from '$stores/tokenInfo';

const log = getLogger('TokenInput');

export let validInput = false;
export let hasEnoughEth: boolean = false;
export let exceedsQuota: boolean = false;

let inputId = `input-${uid()}`;
let inputBox: InputBox;
Expand Down Expand Up @@ -134,6 +139,60 @@
$computingBalance = false;
};

const checkIfAmountExceedsQuota = async () => {
log('checking if amount exceeds quota');
if (!$selectedToken || !$connectedSourceChain || !$destNetwork) return false;

let tokenAddress: Address = zeroAddress;
if ($selectedToken === ETHToken) {
// ETH does not have a token address
} else {
// fetch the correct token address for the destination chain
const tokenInfo = await getTokenAddresses({
token: $selectedToken,
srcChainId: $connectedSourceChain.id,
destChainId: $destNetwork.id,
});
if (!tokenInfo) return false;
log('tokenInfo', tokenInfo);
// get address that matches destination chain
const getAddressForChain = (tokenInfo: TokenInfo, chainId: number): Address | null => {
if (tokenInfo.canonical?.chainId === chainId) {
return tokenInfo.canonical.address;
}
if (tokenInfo.bridged?.chainId === chainId) {
return tokenInfo.bridged.address;
}
return null;
};

const destChainAddress = getAddressForChain(tokenInfo, $destNetwork.id);
log('destChainAddress', destChainAddress);
if (!destChainAddress) return false;
tokenAddress = destChainAddress;
}

try {
const quotaManagerAddress = getContractAddressByType({
srcChainId: Number($destNetwork.id),
destChainId: Number($connectedSourceChain.id),
contractType: ContractType.QUOTAMANAGER,
});

log('quotaManagerAddress', quotaManagerAddress);
exceeds = await checkQuota({
tokenAddress,
amount: $enteredAmount,
quotaManagerAddress,
chainId: $destNetwork.id,
});
log('exceedsQuota', exceeds);
} catch (error) {
// Likely no quota manager for this chain
log('Error checking if amount exceeds quota: ', error);
}
};

let previousSelectedToken = $selectedToken;

$: if ($selectedToken !== previousSelectedToken) {
Expand All @@ -143,7 +202,18 @@

$: disabled = !$account || !$account.isConnected;

$: validAmount = $enteredAmount > BigInt(0);
$: validAmount = $enteredAmount > BigInt(0) && !exceeds;

$: exceeds = false;
$: if (exceeds) {
exceedsQuota = true;
} else {
exceedsQuota = false;
}

$: if ($enteredAmount > 0n) {
checkIfAmountExceedsQuota();
}

$: skipValidate =
!$connectedSourceChain ||
Expand All @@ -156,7 +226,7 @@
let invalidInput: boolean;
$: {
if ($enteredAmount !== 0n) {
invalidInput = $errorComputingBalance || $insufficientBalance || $insufficientAllowance;
invalidInput = $errorComputingBalance || $insufficientBalance || $insufficientAllowance || exceeds;
} else {
invalidInput = false;
}
Expand Down Expand Up @@ -238,12 +308,14 @@
</div>

<div class="flex mt-[8px] min-h-[24px]">
{#if displayFeeMsg}
{#if displayFeeMsg && !exceedsQuota}
<div class="f-row items-center gap-1">
<Icon type="info-circle" size={15} fillClass="fill-tertiary-content" /><span
class="text-sm text-tertiary-content"
>{$t('recipient.label')} <ProcessingFee textOnly class="text-tertiary-content" bind:hasEnoughEth /></span>
</div>
{:else if exceedsQuota}
<FlatAlert type="error" message={$t('bridge.errors.amount_exceeds_quota')} class="relative" />
{:else if showInsufficientBalanceAlert}
<FlatAlert type="error" message={$t('bridge.errors.insufficient_balance.title')} class="relative" />
{:else if showInvalidTokenAlert}
Expand All @@ -254,7 +326,6 @@
</div>
</div>

<OnNetwork change={reset} />
<OnAccount change={reset} />

<style>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@
import { chainConfig } from '$chainConfig';
import { Alert } from '$components/Alert';
import { ProcessingFee, Recipient } from '$components/Bridge/SharedBridgeComponents';
import { destNetwork as destChain, enteredAmount, selectedToken } from '$components/Bridge/state';
import { destNetwork as destChain, enteredAmount, processingFee, selectedToken } from '$components/Bridge/state';
import { PUBLIC_SLOW_L1_BRIDGING_WARNING } from '$env/static/public';
import { LayerType } from '$libs/chain';
import { isStablecoin, isSupported, isWrapped, type Token } from '$libs/token';
import { isStablecoin, isSupported, isWrapped, type Token, TokenType } from '$libs/token';
import { isToken } from '$libs/token/isToken';
import { ethBalance } from '$stores/balance';
import { connectedSourceChain } from '$stores/network';

export let hasEnoughEth: boolean = false;
export let needsManualReviewConfirmation = false;
export let hasEnoughFundsToContinue: boolean = true;

let recipientComponent: Recipient;
let processingFeeComponent: ProcessingFee;
Expand All @@ -38,6 +40,19 @@
needsManualReviewConfirmation = false;
}

$: if ($selectedToken?.type === TokenType.ETH) {
if ($processingFee + $enteredAmount > $ethBalance || !hasEnoughEth) {
hasEnoughFundsToContinue = false;
} else {
hasEnoughFundsToContinue = true;
}
}
// else if (hasEnoughEth && $processingFee !== 0n) {
// hasEnoughFundsToContinue = true;
// } else {
// hasEnoughFundsToContinue = false;
// }

const dispatch = createEventDispatcher();

const editTransactionDetails = () => {
Expand Down Expand Up @@ -85,6 +100,7 @@
<!--
Recipient & Processing Fee
-->

<div class="f-col">
<div class="f-between-center mb-[10px]">
<div class="font-bold text-primary-content">{$t('bridge.nft.step.review.recipient_details')}</div>
Expand All @@ -95,7 +111,9 @@ Recipient & Processing Fee
</div>

<div class="h-sep" />

{#if !hasEnoughFundsToContinue}
<Alert type="error">{$t('bridge.alerts.not_enough_funds')}</Alert>
{/if}
{#if wrapped}
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
<Alert type="warning">{@html wrappedAssetWarning}</Alert>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@
export let activeStep: BridgeSteps = BridgeSteps.IMPORT;
export let validatingImport = false;

export let hasEnoughFundsToContinue: boolean;
export let needsManualReviewConfirmation: boolean;
export let needsManualRecipientConfirmation: boolean;
export let bridgingStatus: BridgingStatus;

export let exceedsQuota: boolean;

let nextStepButtonText: string;
let manuallyConfirmedReviewStep = false;
let manuallyConfirmedRecipientStep = false;
Expand Down Expand Up @@ -77,12 +80,13 @@
<div class="h-sep mt-0" />
<ActionButton
priority="primary"
disabled={!$importDone || disabled}
disabled={!$importDone || disabled || exceedsQuota}
loading={validatingImport}
on:click={() => handleNextStep()}>
<span class="body-bold">{nextStepButtonText}</span>
</ActionButton>
{/if}

{#if activeStep === BridgeSteps.REVIEW}
{#if needsManualReviewConfirmation}
<ActionButton
Expand All @@ -97,7 +101,10 @@
</ActionButton>
{/if}

<ActionButton priority="primary" disabled={disabled || !reviewConfirmed} on:click={() => handleNextStep()}>
<ActionButton
priority="primary"
disabled={disabled || !reviewConfirmed || !hasEnoughFundsToContinue}
on:click={() => handleNextStep()}>
<span class="body-bold">{nextStepButtonText}</span>
</ActionButton>

Expand Down
Loading