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: new transfer flow #3334

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion app/app.nix
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ _: {
{
packages = {
app = jsPkgs.buildNpmPackage {
npmDepsHash = "sha256-YAUgEe+4g4GbKprXJoeMKrkvhUqXZ6md5WJph2DGcEM=";
npmDepsHash = "sha256-KZE/nwYPBiqJEaVyV8vqu/nLmqtb6XrGRvKQwauQWxw=";
src = ./.;
sourceRoot = "app";
npmFlags = [
Expand Down
16 changes: 8 additions & 8 deletions app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
"postinstall": "patch-package"
},
"dependencies": {
"temporal-polyfill": "^0.2.5",
"mode-watcher": "0.5.0",
"svelte-sonner": "^0.3.27",
"@cosmjs/amino": "^0.32.4",
"@cosmjs/cosmwasm-stargate": "0.32.4",
"@cosmjs/encoding": "^0.32.4",
Expand All @@ -35,10 +32,13 @@
"cmdk-sv": "^0.0.18",
"gql.tada": "1.8.10",
"graphql-request": "7.1.2",
"mode-watcher": "0.5.0",
"svelte-persisted-store": "^0.11.0",
"svelte-radix": "^1.1.1",
"svelte-sonner": "^0.3.27",
"temporal-polyfill": "^0.2.5",
"three": "0.170.0",
"valibot": "0.42.1",
"valibot": "1.0.0-beta.9",
"vaul-svelte": "^0.3.2",
"viem": "2.21.52"
},
Expand All @@ -48,7 +48,7 @@
"@iconify-json/lucide": "^1.2.3",
"@iconify-json/mdi": "^1.2.0",
"@iconify-json/tabler": "1.2.8",
"@keplr-wallet/types": "0.12.157",
"@keplr-wallet/types": "^0.12.158",
"@leapwallet/types": "^0.0.5",
"@melt-ui/pp": "^0.3.2",
"@melt-ui/svelte": "^0.83.0",
Expand Down
4 changes: 4 additions & 0 deletions app/src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ interface AptosWindow {
declare global {
namespace App {}

interface EventTarget {
value?: string
}

interface Window extends AptosWindow, KeplrWindow, LeapWindow, Browser, GoogleRecaptcha {
EventEmitter: typeof EventEmitter
}
Expand Down
4 changes: 0 additions & 4 deletions app/src/lib/components/connect/connect.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ let connectedWallets = derived(
}
)

onMount(() => {
console.info($aptosStore)
})

$: if ($connectedWallets >= 1) {
buttonText = $connectedWallets < 3 ? `Connected ${$connectedWallets}/3` : "Connected"
} else {
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/polyfill.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "temporal-polyfill/global"
import EventEmitter from "events"
import EventEmitter from "node:events"
import { browser } from "$app/environment"

if (browser) {
Expand Down
21 changes: 16 additions & 5 deletions app/src/lib/queries/balance/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ export function userBalancesQuery({
connected?: boolean
}) {
return createQueries({
combine: resultArray => ({
data: resultArray.reduce(
(accumulator, current, index) => {
accumulator[chains[index].chain_id] = current.data
return accumulator
},
{} as Record<string, any>
),
pending: resultArray.some(result => result.isLoading)
}),
queries: chains.map(chain => ({
queryKey: [
"balances",
Expand All @@ -37,14 +47,15 @@ export function userBalancesQuery({
.filter(rpc => rpc.type === "alchemy" || rpc.type === "routescan")
.at(0)

if (rpc?.type === "alchemy") {
return await getBalancesFromAlchemy({
if (rpc?.type === "routescan") {
return await getBalancesFromRoutescan({
url: rpc.url,
walletAddress: userAddr.evm.canonical
})
}
if (rpc?.type === "routescan") {
return await getBalancesFromRoutescan({

if (rpc?.type === "alchemy") {
return await getBalancesFromAlchemy({
url: rpc.url,
walletAddress: userAddr.evm.canonical
})
Expand All @@ -61,7 +72,7 @@ export function userBalancesQuery({

return multicallResults
.map((result, index) => ({
balance: result.balance,
balance: BigInt(result.balance),
address: tokenList[index].denom,
name: tokenList[index].display_name,
symbol: tokenList[index].display_symbol,
Expand Down
10 changes: 7 additions & 3 deletions app/src/lib/queries/chains.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { URLS } from "$lib/constants"
import { request } from "graphql-request"
import { createQuery } from "@tanstack/svelte-query"
import { chainsQueryDocument } from "$lib/graphql/queries/chains"

import { request } from "graphql-request"
import { URLS } from "$lib/constants"
export const chainsQueryKeys = {
all: ["chains"] as const,
list: (filters: string) => [...chainsQueryKeys.all, { filters }] as const
}

export const chainsQuery = () =>
createQuery({
queryKey: ["chains"],
queryKey: chainsQueryKeys.all,
placeholderData: (previousData, _) => previousData,
queryFn: async () => (await request(URLS().GRAPHQL, chainsQueryDocument, {})).v1_chains,
enabled: true,
Expand Down
77 changes: 77 additions & 0 deletions app/src/routes/transfer-new/(components)/assets-dialog.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<script lang="ts">
import { formatUnits } from "viem"
import type { Chain } from "$lib/types.ts"
import { cn } from "$lib/utilities/shadcn.ts"
import { truncate } from "$lib/utilities/format"
import * as Dialog from "$lib/components/ui/dialog"
import Precise from "$lib/components/precise.svelte"
import { showUnsupported } from "$lib/stores/user.ts"
import { Button } from "$lib/components/ui/button/index.ts"
import { ScrollArea } from "$lib/components/ui/scroll-area"
import { getSupportedAsset } from "$lib/utilities/helpers.ts"

/**
* TODO: format the balance to a readable format - in order to do that properly, need:
* - the balance,
* - the decimals,
* - whether it's evm or cosmos:
* - if evm then `Number(formatUnits(balance, decimals)).toFixed(2)`, - the 2 can be a 4 if you want more precision
* - if cosmos then: TBD
*/

export let dialogOpen = false
export let chain: Chain
export let assets: Array<{
address: string
balance: bigint
decimals?: number
symbol: string
}>

export let onAssetSelect: (data: { address: string; symbol: string }) => void
</script>

<Dialog.Root
bind:open={dialogOpen}
closeOnEscape={true}
closeOnOutsideClick={true}
preventScroll={true}
>
<Dialog.Content
class="max-w-[90%] sm:max-w-[450px] max-h-[95%] px-0 pt-4 pb-2 flex flex-col items-start"
>
<Dialog.Header class="max-h-min h-8 p-2">
<Dialog.Title class="px-2">Select Asset</Dialog.Title>
</Dialog.Header>
<div class="w-full overflow-scroll">
<ul>
{#each assets as asset, index}
{@const supportedAsset = getSupportedAsset(chain, asset.address)}
{#if $showUnsupported || supportedAsset}
<li
class={cn(
'pb-2 dark:text-accent-foreground flex flex-col h-full justify-start align-middle space-x-3.5',
)}
>
<Button
variant="ghost"
class={cn('size-full px-4 py-2 w-full text-foreground rounded-none flex ')}
on:click={() => {
onAssetSelect({address: asset.address, symbol : (supportedAsset && supportedAsset.display_symbol) || (asset && asset.symbol) || 'Unknown symbol' })
dialogOpen = false
}}
>
<div class="size-full flex flex-col items-start" class:opacity-30={!supportedAsset}>
{truncate((supportedAsset && supportedAsset.display_symbol) || (asset && asset.symbol) || '', 6) || 'Unknown symbol'}
</div>
<p class="mb-auto text-lg font-black" class:opacity-30={!supportedAsset}>
{formatUnits(asset.balance, supportedAsset?.decimals ?? 0)}
</p>
</Button>
</li>
{/if}
{/each}
</ul>
</div>
</Dialog.Content>
</Dialog.Root>
23 changes: 23 additions & 0 deletions app/src/routes/transfer-new/(components)/chain-button.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script lang="ts">
import Chevron from "./chevron.svelte"
import { Button } from "$lib/components/ui/button/index.ts"

export let dialogOpen: boolean
</script>

<Button
{...$$restProps}
variant="outline"
data-transfer-from-chain=""
on:click={() => (dialogOpen = !dialogOpen)}
class="flex flex-row items-center w-full"
>
<div class="flex items-center space-x-1.5 flex-1">
<div class="flex flex-col items-start">
<div class="font-bold text-md mr-auto w-full text-left">
<slot />
</div>
</div>
</div>
<Chevron />
</Button>
54 changes: 54 additions & 0 deletions app/src/routes/transfer-new/(components)/chain-dialog.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<script lang="ts">
import { toast } from "svelte-sonner"
import type { Chain } from "$lib/types.ts"
import { cn } from "$lib/utilities/shadcn.ts"
import { Badge } from "$lib/components/ui/badge"
import * as Dialog from "$lib/components/ui/dialog"
import { Button } from "$lib/components/ui/button/index.js"

export let kind: "from" | "to"
export let dialogOpen = false
export let chains: Array<Chain>
export let selectedChain: string | undefined
export let onChainSelect: (newSelectedChain: string) => void

$: document.body.style.overflow = dialogOpen ? "hidden" : "auto"

const selectChain = (chain: Chain) => [onChainSelect(chain.chain_id), (dialogOpen = false)]
</script>

<Dialog.Root
closeOnEscape={true}
preventScroll={true}
bind:open={dialogOpen}
closeOnOutsideClick={true}
>
<Dialog.Content class={cn('border-solid overflow-auto flex flex-col items-start p-0 pt-4 pb-2')}>
<Dialog.Header class="max-h-min p-2 w-full">
<Dialog.Title class="px-2">
Select {kind} Network
</Dialog.Title>
</Dialog.Header>
<Dialog.Description class="size-full">
<ul class="flex flex-col">
{#each chains as chain, index}
{@const selected = selectedChain === chain.chain_id}
<li class={cn('dark:text-accent-foreground flex flex-col')}>
<Button
variant={'ghost'}
on:click={() => selectChain(chain)}
class={cn(
'size-full px-4 py-2 w-full text-foreground rounded-none flex items-center justify-between dark:hover:text-black',
selected ? 'bg-muted-foreground text-background' : '',
)}
>
<span class="text-lg font-bold">
{chain.display_name}
</span>
</Button>
</li>
{/each}
</ul>
</Dialog.Description>
</Dialog.Content>
</Dialog.Root>
4 changes: 4 additions & 0 deletions app/src/routes/transfer-new/(components)/chevron.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<script lang="ts">
import ChevronDown from "virtual:icons/lucide/chevron-down"
</script>
<ChevronDown class="size-6 text-accent-foreground/60" />
13 changes: 13 additions & 0 deletions app/src/routes/transfer-new/+layout.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script lang="ts">
import ChainsGate from "$lib/components/chains-gate.svelte"
</script>

<svelte:head>
<title>Union | Send</title>
</svelte:head>

<ChainsGate let:chains>
<div class="w-full flex flex-col items-center">
<slot {chains} />
</div>
</ChainsGate>
Loading
Loading