Skip to content

Commit

Permalink
feat(bridge-ui-v2): bridging ETH and ERC20 (#14225)
Browse files Browse the repository at this point in the history
  • Loading branch information
jscriptcoder authored Jul 24, 2023
1 parent e71d558 commit c3375a4
Show file tree
Hide file tree
Showing 50 changed files with 1,285 additions and 453 deletions.
4 changes: 4 additions & 0 deletions packages/bridge-ui-v2/src/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ export const bridge = {
noOwnerGasLimit: BigInt(140000),
noTokenDeployedGasLimit: BigInt(3000000),
};

export const pendingTransaction = {
waitTimeout: 300000,
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import TableView from './TableView.svelte';
</script>

<Card class="md:min-w-[524px]" title={$t('activities.title')} text={$t('activities.subtitle')}>
<Card class="md:min-w-[524px]" title={$t('activities.title')} text={$t('activities.description')}>
<div class="space-y-[35px]">
<ChainSelector label={$t('chain_selector.currently_on')} value={$network} />
<ChainSelector label={$t('chain_selector.currently_on')} value={$network} small />
<!-- Small size view -->
<div class="md:hidden">
<ListWithDetailsView />
Expand Down
24 changes: 11 additions & 13 deletions packages/bridge-ui-v2/src/components/Alert/Alert.svelte
Original file line number Diff line number Diff line change
@@ -1,49 +1,47 @@
<script lang="ts">
import { classNames } from '$libs/util/classNames';
import { Icon, type IconType } from '../Icon';
import { Icon } from '../Icon';
import type { AlertIconDetails, AlertType } from './types';
type AlertType = 'success' | 'warning' | 'error' | 'info';
type AlertTypeDetails = {
class: string;
iconType: IconType;
iconFillClass: string;
type AlertTypeDetails = AlertIconDetails & {
alertClass: string;
};
export let type: AlertType;
export let forceColumnFlow = false;
let typeMap: Record<AlertType, AlertTypeDetails> = {
success: {
class: 'alert-success',
alertClass: 'alert-success',
iconType: 'check-circle',
iconFillClass: 'fill-success-content',
},
warning: {
class: 'alert-warning',
alertClass: 'alert-warning',
iconType: 'exclamation-circle',
iconFillClass: 'fill-warning-content',
},
error: {
class: 'alert-danger',
alertClass: 'alert-danger',
iconType: 'x-close-circle',
iconFillClass: 'fill-error-content',
},
info: {
class: 'alert-info',
alertClass: 'alert-info',
iconType: 'info-circle',
iconFillClass: 'fill-info-content',
},
};
const { alertClass, iconType, iconFillClass } = typeMap[type];
const classes = classNames(
'alert flex gap-[5px] py-[12px] px-[20px] rounded-[10px]',
type ? typeMap[type].class : null,
type ? alertClass : null,
forceColumnFlow ? 'grid-flow-col text-left' : null,
$$props.class,
);
const iconType = typeMap[type].iconType;
const iconFillClass = typeMap[type].iconFillClass;
</script>

<div class={classes}>
Expand Down
47 changes: 47 additions & 0 deletions packages/bridge-ui-v2/src/components/Alert/FlatAlert.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<script lang="ts">
import { classNames } from '$libs/util/classNames';
import { Icon } from '../Icon';
import type { AlertIconDetails, AlertType } from './types';
type AlertTypeDetails = AlertIconDetails & {
textClass: string;
};
export let type: AlertType;
export let message: string;
let typeMap: Record<AlertType, AlertTypeDetails> = {
success: {
textClass: 'text-positive-sentiment',
iconType: 'check-circle',
iconFillClass: 'fill-success-content',
},
warning: {
textClass: 'text-warning-sentiment',
iconType: 'exclamation-circle',
iconFillClass: 'fill-warning-content',
},
error: {
textClass: 'text-negative-sentiment',
iconType: 'x-close-circle',
iconFillClass: 'fill-error-content',
},
info: {
textClass: 'text-secondary-content',
iconType: 'info-circle',
iconFillClass: 'fill-info-content',
},
};
const { textClass, iconType, iconFillClass } = typeMap[type];
const classes = classNames('f-items-center space-x-1', $$props.class);
</script>

<div class={classes}>
<Icon type={iconType} fillClass={iconFillClass} />
<div class="body-small-regular {textClass}">
{message}
</div>
</div>
1 change: 1 addition & 0 deletions packages/bridge-ui-v2/src/components/Alert/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as Alert } from './Alert.svelte';
export { default as FlatAlert } from './FlatAlert.svelte';
8 changes: 8 additions & 0 deletions packages/bridge-ui-v2/src/components/Alert/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { IconType } from '$components/Icon';

export type AlertType = 'success' | 'warning' | 'error' | 'info';

export type AlertIconDetails = {
iconType: IconType;
iconFillClass: string;
};
96 changes: 96 additions & 0 deletions packages/bridge-ui-v2/src/components/Bridge/Actions.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<script lang="ts">
import { t } from 'svelte-i18n';
import { Button } from '$components/Button';
import { Icon } from '$components/Icon';
import { TokenType } from '$libs/token';
import { account, network } from '$stores';
import {
computingBalance,
destNetwork,
enteredAmount,
errorComputingBalance,
insufficientAllowance,
insufficientBalance,
recipientAddress,
selectedToken,
tokenBalance,
} from './state';
export let approve: () => Promise<void>;
export let bridge: () => Promise<void>;
let approving = false;
let bridging = false;
function onApproveClick() {
approving = true;
approve().finally(() => {
approving = false;
});
}
function onBridgeClick() {
bridging = true;
bridge().finally(() => {
bridging = false;
});
}
// TODO: feels like we need a state machine here
// Basic conditions so we can even start the bridging process
$: hasAddress = $recipientAddress || $account?.address;
$: hasNetworks = $network?.id && $destNetwork?.id;
$: hasBalance =
!$computingBalance && !$errorComputingBalance && $tokenBalance?.value && $tokenBalance?.value > BigInt(0);
$: canDoNothing = !hasAddress || !hasNetworks || !hasBalance || !$selectedToken || !$enteredAmount;
// Conditions for approve/bridge steps
$: isSelectedERC20 = $selectedToken && $selectedToken.type === TokenType.ERC20;
$: isTokenApproved = isSelectedERC20 && $enteredAmount && !$insufficientAllowance;
// Conditions to disable/enable buttons
$: disableApprove = canDoNothing || !$insufficientAllowance || approving;
$: disableBridge = canDoNothing || $insufficientAllowance || $insufficientBalance || bridging;
// General loading state
$: loading = approving || bridging;
</script>

<div class="f-between-center w-full gap-4">
{#if isSelectedERC20}
<Button
type="primary"
class="px-[28px] py-[14px] rounded-full flex-1"
disabled={disableApprove}
loading={approving}
on:click={onApproveClick}>
{#if approving}
<span class="body-bold">{$t('bridge.button.approving')}</span>
{:else if isTokenApproved}
<div class="f-items-center">
<Icon type="check" />
<span class="body-bold">{$t('bridge.button.approved')}</span>
</div>
{:else}
<span class="body-bold">{$t('bridge.button.approve')}</span>
{/if}
</Button>
<Icon type="arrow-right" />
{/if}

<Button
type="primary"
class="px-[28px] py-[14px] rounded-full flex-1"
disabled={disableBridge}
loading={bridging}
on:click={onBridgeClick}>
{#if bridging}
<span class="body-bold">{$t('bridge.button.bridging')}</span>
{:else}
<span class="body-bold">{$t('bridge.button.bridge')}</span>
{/if}
</Button>
</div>
Loading

0 comments on commit c3375a4

Please sign in to comment.