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-v2): Addition of custom token #14365

Merged
merged 10 commits into from
Aug 6, 2023
1 change: 1 addition & 0 deletions packages/bridge-ui-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-svelte": "^2.26.0",
"ethereum-address": "^0.0.4",
"jsdom": "^22.1.0",
"postcss": "^8.4.24",
"prettier": "^3.0.0",
"prettier-plugin-svelte": "^3.0.0",
Expand Down
36 changes: 18 additions & 18 deletions packages/bridge-ui-v2/src/components/Bridge/AddressInput.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { isAddress } from 'ethereum-address';
import { createEventDispatcher } from 'svelte';
import { t } from 'svelte-i18n';
import type { Address } from 'viem';

import { Alert } from '$components/Alert';
import { uid } from '$libs/util/uid';
Expand All @@ -10,38 +11,35 @@
let inputId = `input-${uid()}`;
let showAlert = true;

let ethereumAddress = '';
export let ethereumAddress: Address | string = '';

let isValidEthereumAddress = false;
let tooShort = true;
const dispatch = createEventDispatcher();

// TODO: nope!!, this should go inside a function whose arguments
// are the values that trigger reactivity
$: {
ethereumAddress;
if (ethereumAddress.length > 41) {
tooShort = false;
validateEthereumAddress();
} else {
const validateEthereumAddress = (address: string | EventTarget | null) => {
if (address && address instanceof EventTarget) {
address = (address as HTMLInputElement).value;
}
const addr = address as string;
if (addr.length < 42) {
tooShort = true;
} else {
tooShort = false;
isValidEthereumAddress = isAddress(addr);
dispatch('input', addr);
}
dispatch('addressvalidation', { isValidEthereumAddress, ethereumAddress });
}

const validateEthereumAddress = () => {
isValidEthereumAddress = isAddress(ethereumAddress);
dispatch('addressvalidation', { isValidEthereumAddress, addr });
};

$: validateEthereumAddress(ethereumAddress);

export const clear = () => {
input.value = '';
validateEthereumAddress();
validateEthereumAddress('');
};

export const focus = () => input.focus();
export const value = () => {
return input.value;
};
</script>

<div class="f-col space-y-2">
Expand All @@ -54,12 +52,14 @@
type="string"
placeholder="0x1B77..."
bind:value={ethereumAddress}
on:input={(e) => validateEthereumAddress(e.target)}
class="w-full input-box outline-none py-6 pr-16 px-[26px] title-subsection-bold placeholder:text-tertiary-content" />
</div>
</div>
<div>
{#if !isValidEthereumAddress && !tooShort}
<Alert type="error" forceColumnFlow>
<!-- TODO: i18n! -->
<p class="font-bold">Invalid address</p>
<p>This doesn't seem to be a valid Ethereum address</p>
</Alert>
Expand Down
51 changes: 28 additions & 23 deletions packages/bridge-ui-v2/src/components/Bridge/Amount.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
import type { ERC20Bridge } from '$libs/bridge/ERC20Bridge';
import { chainContractsMap } from '$libs/chain';
import { InsufficientAllowanceError, InsufficientBalanceError, RevertedWithFailedError } from '$libs/error';
import { getAddress,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 { getLogger } from '$libs/util/logger';
import { truncateString } from '$libs/util/truncateString';
import { uid } from '$libs/util/uid';
import { account } from '$stores/account';
Expand All @@ -33,14 +34,12 @@
tokenBalance,
} from './state';

const log = getLogger('component:Amount');

let inputId = `input-${uid()}`;
let inputBox: InputBox;
let computingMaxAmount = false;

onMount(() => {
clearAmount();
});

// Public API
export function clearAmount() {
inputBox.clear();
Expand All @@ -58,7 +57,9 @@
!$network ||
!$destNetwork ||
!$tokenBalance ||
$enteredAmount === BigInt(0) // no need to check if the amount is 0
!$selectedToken ||
$enteredAmount === BigInt(0) || // no need to check if the amount is 0
$tokenBalance.symbol !== $selectedToken.symbol
) {
$insufficientBalance = false;
return;
Expand Down Expand Up @@ -103,8 +104,6 @@
destChainId: $destNetwork.id,
});
} catch (err) {
console.error(err);

switch (true) {
case err instanceof InsufficientBalanceError:
$insufficientBalance = true;
Expand Down Expand Up @@ -138,8 +137,10 @@
userAddress,
});
} catch (err) {
console.error(err);
log('Error updating balance: ', err);
//most likely we have a custom token that is not bridged yet
$errorComputingBalance = true;
clearAmount();
} finally {
$computingBalance = false;
}
Expand Down Expand Up @@ -195,7 +196,7 @@
// Check validity
validateAmount();
} catch (err) {
console.error(err);
log('Error in getting maxAmount ', err);
warningToast($t('amount_input.button.failed_max'));
} finally {
computingMaxAmount = false;
Expand All @@ -211,16 +212,19 @@
<div class="f-between-center text-secondary-content">
<label class="body-regular" for={inputId}>{$t('amount_input.label')}</label>
<div class="body-small-regular">
<span>{$t('amount_input.balance')}:</span>
<span>
{#if $computingBalance}
<LoadingText mask="0.0000" />
<LoadingText mask="XXX" />
{:else}
{renderBalance($tokenBalance)}
{/if}
<!-- TODO: we know when there was an error computing. Show it -->
</span>
{#if $errorComputingBalance}
<FlatAlert type="error" message={$t('bridge.errors.cannot_fetch_balance')} />
{:else}
<span>{$t('amount_input.balance')}:</span>
<span>
{#if $computingBalance}
<LoadingText mask="0.0000" />
<LoadingText mask="XXX" />
{:else}
{renderBalance($tokenBalance)}
{/if}
</span>
{/if}
</div>
</div>

Expand All @@ -230,6 +234,7 @@
id={inputId}
type="number"
placeholder="0.01"
disabled={$errorComputingBalance}
min="0"
loading={computingMaxAmount}
error={$insufficientBalance}
Expand All @@ -239,14 +244,14 @@
<!-- TODO: talk to Jane about the MAX button and its styling -->
<button
class="absolute right-6 uppercase hover:font-bold"
disabled={!$selectedToken || !$network || computingMaxAmount}
disabled={!$selectedToken || !$network || computingMaxAmount || $errorComputingBalance}
on:click={useMaxAmount}>
{$t('amount_input.button.max')}
</button>
</div>
{#if $insufficientBalance && $enteredAmount > 0}
{#if $insufficientBalance && $enteredAmount > 0 && !errorComputingBalance}
<FlatAlert type="error" message={$t('error.insufficient_balance')} class="absolute bottom-[-26px]" />
{:else if $insufficientAllowance && $enteredAmount > 0}
{:else if $insufficientAllowance && $enteredAmount > 0 && !errorComputingBalance}
<FlatAlert type="warning" message={$t('error.insufficient_allowance')} class="absolute bottom-[-26px]" />
{/if}
</div>
Expand Down
21 changes: 21 additions & 0 deletions packages/bridge-ui-v2/src/components/Icon/ERC20.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script lang="ts">
export let height = 30;
export let width = 30;
</script>

<svg
xmlns="http://www.w3.org/2000/svg"
class="bg-white !rounded-full"
{height}
{width}
preserveAspectRatio="xMidYMid"
viewBox="-38.39985 -104.22675 332.7987 625.3605"
><path fill="#343434" d="M125.166 285.168l2.795 2.79 127.962-75.638L127.961 0l-2.795 9.5z" /><path
fill="#8C8C8C"
d="M127.962 287.959V0L0 212.32z" /><path
fill="#3C3C3B"
d="M126.386 412.306l1.575 4.6L256 236.587l-128.038 75.6-1.575 1.92z" /><path
fill="#8C8C8C"
d="M0 236.585l127.962 180.32v-104.72z" /><path fill="#141414" d="M127.961 154.159v133.799l127.96-75.637z" /><path
fill="#393939"
d="M127.96 154.159L0 212.32l127.96 75.637z" /></svg>
23 changes: 21 additions & 2 deletions packages/bridge-ui-v2/src/components/Icon/Icon.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,28 @@
| 'up-down-circle'
| 'check-circle'
| 'info-circle'
| 'plus-circle'
| 'circle'
| 'arrow-right'
| 'up-down'
| 'check';
| 'check'
| 'trash';
</script>

<script lang="ts">
export let type: IconType;
export let size = 20;
export let width = size;
export let height = size;
export let minX = 0;
export let minY = 0;
export let vWidth = width;
export let vHeight = height;
export let viewBox = `${minX} ${minY} ${vWidth} ${vHeight}`;
export let fillClass = 'fill-primary-icon';
</script>

<svg {width} {height} class={$$props.class} viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg {width} {height} class={$$props.class} {viewBox} fill="none" xmlns="http://www.w3.org/2000/svg">
{#if type === 'bridge'}
<path
class={fillClass}
Expand Down Expand Up @@ -123,6 +130,12 @@
fill-rule="evenodd"
clip-rule="evenodd"
d="M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10ZM11 6C11 6.55228 10.5523 7 10 7C9.44771 7 9 6.55228 9 6C9 5.44772 9.44771 5 10 5C10.5523 5 11 5.44772 11 6ZM9 9C8.58579 9 8.25 9.33579 8.25 9.75C8.25 10.1642 8.58579 10.5 9 10.5H9.25338C9.41332 10.5 9.53213 10.6481 9.49743 10.8042L9.03829 12.8704C8.79542 13.9633 9.62706 15 10.7466 15H11C11.4142 15 11.75 14.6642 11.75 14.25C11.75 13.8358 11.4142 13.5 11 13.5H10.7466C10.5867 13.5 10.4679 13.3519 10.5026 13.1958L10.9617 11.1296C11.2046 10.0367 10.3729 9 9.25338 9H9Z" />
{:else if type === 'plus-circle'}
<path
class={fillClass}
fill-rule="evenodd"
clip-rule="evenodd"
d="M15.5 29.5c-7.18 0-13-5.82-13-13s5.82-13 13-13 13 5.82 13 13-5.82 13-13 13zM21.938 15.938c0-0.552-0.448-1-1-1h-4v-4c0-0.552-0.447-1-1-1h-1c-0.553 0-1 0.448-1 1v4h-4c-0.553 0-1 0.448-1 1v1c0 0.553 0.447 1 1 1h4v4c0 0.553 0.447 1 1 1h1c0.553 0 1-0.447 1-1v-4h4c0.552 0 1-0.447 1-1v-1z" />
{:else if type === 'circle'}
<circle class={fillClass} cx="10" cy="10" r="6" />
{:else if type === 'arrow-right'}
Expand All @@ -145,5 +158,11 @@
clip-rule="evenodd"
d="M16.7045 4.15347C17.034 4.4045 17.0976 4.87509 16.8466 5.20457L8.84657 15.7046C8.71541 15.8767 8.51627 15.9838 8.30033 15.9983C8.08439 16.0129 7.87271 15.9334 7.71967 15.7804L3.21967 11.2804C2.92678 10.9875 2.92678 10.5126 3.21967 10.2197C3.51256 9.92682 3.98744 9.92682 4.28033 10.2197L8.17351 14.1129L15.6534 4.29551C15.9045 3.96603 16.3751 3.90243 16.7045 4.15347Z" />
</svg>
{:else if type === 'trash'}
<path
class={fillClass}
fill-rule="evenodd"
clip-rule="evenodd"
d="M20,6H16V5a3,3,0,0,0-3-3H11A3,3,0,0,0,8,5V6H4A1,1,0,0,0,4,8H5V19a3,3,0,0,0,3,3h8a3,3,0,0,0,3-3V8h1a1,1,0,0,0,0-2ZM10,5a1,1,0,0,1,1-1h2a1,1,0,0,1,1,1V6H10Zm7,14a1,1,0,0,1-1,1H8a1,1,0,0,1-1-1V8H17Z" />
{/if}
</svg>
Loading