Skip to content

Commit

Permalink
EVM bridge with design (#164)
Browse files Browse the repository at this point in the history
* chore: added evm-bridge page

* chore: added link to evm-swap page

* chore: added native swap page

* chore: added evmToNativeTransfer section

* fix: getting the /evm/swap pages working

* refactor: renamed transfer functions

* chore: styled the evm swap page

* fix: got the native to evm swap working

* fix: got the evm section working

* style: linted

* Removed package-lock.json and rebuilt yarn.lock

* refactor: moved evm logic to separate file

* fix: getting site building

* enhancement: polishing swap page

* enhancement: polishing of the swap page form

* chore: moved select to element component

* enhancement: polishing of the swap confirm page

* enhancement: added EOS native balance

* enhancement: added EVM EOS balance

* enhancement: added basic validation

* enhancement: better error handling

* enhancement: polished the swap success page

* enhancement: general polishing of evm bridge

* style: linted

* enhancement: polished the error page

* enhancement: connecting to evm wallet on page load

* chore: trying to connect to eth wallet automatically every 3 seconds

* enhancement: general polishing of new transfer page

* enhancement: making transfer confirm screen bigger

* enhancement: clearing the form when changing active session

* refactor: using from and to instead of transferOption

* enhancement: using the token selector to let users select account

* fix: getting the token selector working with evm swap form

* enhancement: general polishing of evm swap form

* enhancement: added selectedToken to TokenSelector

* fix: only allowing form submission once both from and to tokens are selected

* enhancement: making the evm swap section look decent on mobile

* style: linted

* enhancement: added ability to pass string instead of balance

* fix: removed border on transfer confirm page

* chore: using /send and /transfer as urls

* fix: preventing submit if not connected to evm wallet

* enhancement: displaying fee amount on confirmation page

* fix: handling useEntireBalance case gracefully

* style: linted

* enhancement: making sure that evm provider is always accessible

* enhancement: updating the balances after transfer

* style: linted

* enhancement: adding fee to transfer amount as opposed to removing it

* chore: displaying fee and net amount in form

* enhancement: styled the confirm page

* enhancement: calculating fee every time an input changes

* enhancement: useEntireBalance now takes into account transferFee

* enhancement: displaying error when funds are insufficient to cover the transfer fee

* chore: added EvmTxFollower component

* enhancement: adding customization props to TxFollower components

* fix: resetting the form properly when appropriate

* chore: displaying usd prices on confirm page

* enhancement: displaying EOS token on confirmation page

* style: linted

---------

Co-authored-by: Aaron Cox <[email protected]>
  • Loading branch information
dafuga and aaroncox committed Sep 22, 2023
1 parent 6c1cd34 commit 3104f9c
Show file tree
Hide file tree
Showing 49 changed files with 1,895 additions and 233 deletions.
5 changes: 5 additions & 0 deletions global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare global {
interface Window {
ethereum: any
}
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
"@types/feather-icons": "^4.7.0",
"anchor-link": "^3.3.0",
"anchor-link-browser-transport": "^3.2.0",
"bn.js": "^5.2.1",
"ethers": "^5.6.9",
"feather-icons": "^4.28.0",
"idb": "^7.0.1",
"inter-ui": "^3.15.0",
Expand All @@ -37,6 +39,7 @@
"@snowpack/plugin-svelte": "^3.4.0",
"@snowpack/plugin-typescript": "^1.1.1",
"@snowpack/plugin-webpack": "^3.0.0",
"@types/bn.js": "^5.1.1",
"@types/pako": "^1.0.1",
"@types/snowpack-env": "^2.3.2",
"@typescript-eslint/eslint-plugin": "^4.22.1",
Expand Down
14 changes: 9 additions & 5 deletions src/app.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
import Login from '~/pages/login.svelte'
import Dashboard from '~/pages/dashboard/index.svelte'
import Request from '~/pages/request/index.svelte'
import Transfer from '~/pages/transfer/index.svelte'
import Send from '~/pages/send/index.svelte'
import TokensPurchase from '~/pages/tokens/purchase/index.svelte'
import Resources from '~/pages/resources/index.svelte'
import Components from '~/pages/_components/index.svelte'
import Loading from '~/pages/loading.svelte'
import Toasts from '~/components/elements/toasts.svelte'
import BanxaSuccess from '~/pages/banxa/success.svelte'
import BanxaFailure from '~/pages/banxa/failure.svelte'
import Transfer from '~/pages/transfer/index.svelte'
$: {
document.body.classList.toggle('darkmode', $darkMode)
Expand Down Expand Up @@ -177,14 +178,14 @@
<Route path="/">
<Dashboard />
</Route>
<Route path="/transfer">
<Transfer />
<Route path="/send">
<Send />
</Route>
<Route path="/tokens/buy">
<TokensPurchase />
</Route>
<Route path="/transfer/:contract/:token" let:meta>
<Transfer {meta} />
<Route path="/send/:contract/:token" let:meta>
<Send {meta} />
</Route>
<Route path="/request/:payload">
<Request />
Expand All @@ -198,6 +199,9 @@
<Route path="/banxa/failure">
<BanxaFailure />
</Route>
<Route path="/transfer">
<Transfer />
</Route>
<Route fallback>
<Page title="Page not found">
<p>You shouldn't be here. Get out before it's too late.</p>
Expand Down
2 changes: 2 additions & 0 deletions src/components/elements/button.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
if (href === undefined) {
event.preventDefault()
}
if (!formValidation || (!$formDisabled && !disabled)) {
dispatch('action', event)
}
Expand Down Expand Up @@ -195,6 +196,7 @@
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
&.loading {
:global(.content .icon:not(.loading)) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/elements/form/transaction.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
let error: boolean = false
let errorMessage: string = ''
let transaction_id = writable<string | undefined>(undefined)
let refreshInterval: number
let refreshInterval: NodeJS.Timeout
function refreshAccount(account_name: Name) {
// Refresh the account data
Expand Down
15 changes: 11 additions & 4 deletions src/components/elements/input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
import type {InputResponse} from 'src/ui-types'
import type {Form} from '~/ui-types'
import {createEventDispatcher} from 'svelte'
import type {inputType} from '~/ui-types'
export let disabled: boolean = false
export let focus: boolean = false
export let inputmode: string = ''
export let inputmode: inputType = undefined
export let name: string = ''
export let placeholder: string = ''
export let value: string = ''
const inputmodeParam = inputmode as any
/** Whether or not the button should go full width */
export let fluid: boolean = false
Expand All @@ -19,7 +22,7 @@
export let isValid: any = () => true
export let assumeValid: boolean = false
let timer: number | undefined
let timer: NodeJS.Timeout | undefined
let delay: number = 300
// Get parent form context (if exists)
Expand Down Expand Up @@ -59,7 +62,7 @@
type HTMLInputFormEvent = Event & {currentTarget: EventTarget & HTMLInputElement}
const debounce = (e: HTMLInputFormEvent) => {
clearTimeout(timer)
timer && clearTimeout(timer)
value = e.currentTarget.value
// Immediately invalidate
invalidate(name, value)
Expand All @@ -78,6 +81,10 @@
}, delay)
}
const handleInput = (e: HTMLInputFormEvent): void => debounce(e)
$: {
isValid(value)
}
</script>

<style type="scss">
Expand Down Expand Up @@ -110,7 +117,7 @@
type="text"
{name}
{disabled}
{inputmode}
inputmode={inputmodeParam}
{placeholder}
bind:this={ref}
bind:value
Expand Down
4 changes: 3 additions & 1 deletion src/components/elements/input/account.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
import {validatePresence} from './validators/presence'
import {validateAccountLength} from './validators/account'
import type {inputType} from '~/ui-types'
// Generic input type matching
export let name: string = ''
export let fluid: boolean = false
export let focus: boolean = false
export let inputmode: string = ''
export let inputmode: inputType = undefined
export let placeholder: string | undefined = undefined
export let value: string = ''
Expand Down
5 changes: 3 additions & 2 deletions src/components/elements/input/label.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
<script>
export let align: 'center' | 'left' | 'right' = 'center'
</script>

<style type="scss">
Expand All @@ -13,6 +14,6 @@
}
</style>

<div class="label">
<div class="label" style="text-align: {align};">
<slot />
</div>
3 changes: 2 additions & 1 deletion src/components/elements/input/labelled.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<script lang="ts">
import Input from '~/components/elements/input.svelte'
import ErrorMessage from './errorMessage.svelte'
import type {inputType} from '~/ui-types'
export let errorMessage: string | undefined = undefined
export let name: string = ''
export let fluid: boolean = false
export let focus: boolean = false
export let inputmode: string = ''
export let inputmode: inputType = null
export let isValid: any = () => true
export let placeholder: string | undefined = undefined
export let value: string = ''
Expand Down
94 changes: 70 additions & 24 deletions src/components/elements/input/token/selector.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
import TokenSelectorRow from './selector/row.svelte'
export let defaultToken: Token
export let defaultToken: Token | undefined = undefined
export let selectedToken: Token | undefined = undefined
export let tokenOptions: Token[] | undefined = undefined
export let onTokenSelect: (token: Token) => void
let selectedToken = defaultToken
let displayModal = writable<boolean>(false)
let query: string = ''
Expand All @@ -34,17 +35,21 @@
let filteredTokens: Token[] = []
$: {
filteredTokens =
($tokens &&
$tokens.filter((token) => {
const blockchainMatches = token.chainId.equals($activeBlockchain.chainId)
const queryExists = query.length === 0
const queryMatches = String(token.name)
.toLowerCase()
.includes(query.toLowerCase())
return blockchainMatches && (queryExists || queryMatches)
})) ||
[]
if (tokenOptions) {
filteredTokens = tokenOptions
} else {
filteredTokens =
($tokens &&
$tokens.filter((token) => {
const blockchainMatches = token.chainId.equals($activeBlockchain.chainId)
const queryExists = query.length === 0
const queryMatches = String(token.name)
.toLowerCase()
.includes(query.toLowerCase())
return blockchainMatches && (queryExists || queryMatches)
})) ||
[]
}
}
</script>

Expand Down Expand Up @@ -100,23 +105,52 @@
}
}
}
.placeholder {
padding: 10px 12px;
border-radius: 12px;
max-width: 400px;
border: 1px solid var(--divider-grey);
display: flex;
align-items: center;
cursor: pointer;
.text-container {
flex: 1;
font-family: Inter;
font-style: normal;
font-weight: 500;
font-size: 14px;
letter-spacing: -0.04px;
color: var(--main-black);
display: inline;
text-align: left;
}
.arrow-container {
display: flex;
width: 20px;
}
}
</style>

<Modal display={displayModal} hideCloseButton>
<div on:click={() => ($displayModal = false)} class="close-button">
<Icon name="x" />
</div>
<h2>Select Token</h2>
<Form>
<Input
on:changed={updateQuery}
value={query}
name="query"
focus
fluid
placeholder="Search tokens..."
/>
</Form>
{#if !tokenOptions}
<Form>
<Input
on:changed={updateQuery}
value={query}
name="query"
focus
fluid
placeholder="Search tokens..."
/>
</Form>
{/if}
<div class="table-container">
<table>
<tr>
Expand Down Expand Up @@ -147,4 +181,16 @@
</div>
</Modal>

<TokenSelectorRow onClick={() => ($displayModal = true)} token={selectedToken} />
{#if selectedToken}
<TokenSelectorRow
onClick={() => ($displayModal = true)}
token={selectedToken || defaultToken}
/>
{:else}
<div class="placeholder" on:click={() => ($displayModal = true)}>
<span class="text-container"> Select Token </span>
<div class="arrow-container">
<Icon name="chevron-right" size="large" />
</div>
</div>
{/if}
15 changes: 11 additions & 4 deletions src/components/elements/input/token/selector/row.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,18 @@
let balance
$: {
balance = $balances && $balances.find((balance) => balance.tokenKey === token.key)
if (token.balance) {
balance = token.balance
} else {
balance =
$balances && $balances.find((balance) => balance.tokenKey === token.key)?.quantity
}
if (balance) {
const tokenPrecision = balance.quantity.symbol.precision
const unitValue = balance.quantity.units.value
if (typeof balance === 'string') {
formattedTokenBalance = balance
} else if (balance) {
const tokenPrecision = balance.symbol.precision
const unitValue = balance.units.value
const fullTokenBalanceString = (
Number(unitValue) / Math.pow(10, tokenPrecision)
).toFixed(tokenPrecision)
Expand Down
47 changes: 47 additions & 0 deletions src/components/elements/select.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<script lang="ts">
import {createEventDispatcher} from 'svelte'
const dispatch = createEventDispatcher()
interface Option {
value: string
label: string
}
export let value = ''
export let options: Option[] = []
export let fluid: boolean = false
function handleChange(event: Event) {
value = (event.target as HTMLSelectElement).value
dispatch('change', value)
}
</script>

<style type="scss">
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 170px;
padding: 10px 12px;
margin-bottom: 15px;
border: 1px solid var(--dark-grey);
border-radius: 12px;
background-color: var(--main-grey);
font-size: 12px;
color: var(--main-black);
&.fullWidth {
width: 100%;
}
}
</style>

<select class={fluid ? 'fullWidth' : ''} bind:value on:change={handleChange}>
{#each options as option (option.value)}
<option value={option.value}>
{option.label}
</option>
{/each}
</select>
Loading

0 comments on commit 3104f9c

Please sign in to comment.