Skip to content

Commit

Permalink
Merge pull request #263 from davidediak/dd/259-token-sorting
Browse files Browse the repository at this point in the history
Dd/259 token sorting
  • Loading branch information
0xIchigo authored Dec 20, 2023
2 parents ec5c40a + a3a7377 commit f17f3e9
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 94 deletions.
28 changes: 23 additions & 5 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ import type { ComponentType } from "svelte";

import type { EnrichedTransaction } from "helius-sdk";

import type {
ProtonActionType,
ProtonTransaction,
ProtonTransactionAction,
} from "$lib/xray";
import type { ProtonTransaction, ProtonTransactionAction } from "$lib/xray";

import type { IconPaths, modals } from "$lib/config";
import type { SOL } from "$lib/xray";

export * from "$lib/config";

Expand Down Expand Up @@ -123,3 +120,24 @@ export interface TokenMap {
export type RecognizedTokens = {
[key: string]: string;
};

/** Used in the account/tokens page */
export type UIAccountToken = {
id: string;
decimals: number;
balance: number;
balanceInUSD: number;
price: number;
fullMetadata: any;
};

/**
* Used in the account/tokens page. A special case for SOL is necessary because
* it's not structed like other tokens
*/
export type UISolAccountToken = {
id: typeof SOL;
balance: number;
balanceInUSD: number;
price: number;
};
206 changes: 117 additions & 89 deletions src/routes/account/[account]/tokens/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<script>
<script lang="ts">
import { trpcWithQuery } from "$lib/trpc/client";
import { page } from "$app/stores";
import TokenProvider from "$lib/components/providers/token-provider.svelte";
import type { UIAccountToken, UISolAccountToken } from "$lib/types";
import formatMoney from "$lib/util/format-money";
import { SOL } from "$lib/xray";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
import formatMoney from "$lib/util/format-money";
const account = $page.params.account;
Expand All @@ -16,107 +17,134 @@
const network = params.get("network");
const isMainnetValue = network !== "devnet";
const tokens = client.searchAssets.createQuery({
const toUIAccountToken = (tokenData: any): UIAccountToken => {
const balance = tokenData.token_info.balance;
const price = tokenData.token_info.price_info?.price_per_token ?? 0;
const decimals = tokenData.token_info.decimals;
return {
balance,
balanceInUSD: (price * balance) / 10 ** decimals,
decimals,
fullMetadata: tokenData,
id: tokenData.id,
price,
};
};
const toUISolAccountToken = (
lamports: number,
price: number = 0
): UISolAccountToken => {
const balance = lamports / LAMPORTS_PER_SOL;
return {
balance,
balanceInUSD: price * balance,
id: SOL,
price,
};
};
const isSol = (
t: UIAccountToken | UISolAccountToken
): t is UISolAccountToken => t.id === SOL;
const getTokensRequest = client.searchAssets.createQuery({
account,
isMainnet: isMainnetValue,
nativeBalance: true,
tokenType: "fungible",
});
const sol = client.price.createQuery(SOL);
const getSolPrice = client.price.createQuery(SOL);
$: getTokensRequestItems = ($getTokensRequest?.data?.items ?? []) as [];
$: lamports = $getTokensRequest?.data?.nativeBalance?.lamports ?? 0;
$: solToken = toUISolAccountToken(lamports, $getSolPrice.data);
$: partialTokens = getTokensRequestItems.map(toUIAccountToken);
$: tokens = [solToken, ...partialTokens].toSorted(
(a, b) => b.balanceInUSD - a.balanceInUSD
);
</script>

<div>
<a
class="mb-4 grid grid-cols-12 items-center gap-3 rounded-lg border px-3 py-2 hover:border-primary"
href="/token/{SOL}"
>
<div class="col-span-2 p-1 md:col-span-1">
<!-- background so that if it doesn't load you dont' get ugly no image icons -->
<div
style="background-image: url(/media/tokens/solana.png)"
class="aspect-square w-full rounded-lg bg-cover"
/>
</div>
<div
class="col-span-10 flex items-center justify-between text-right md:col-span-11"
>
<div>
<h4 class="font-semibold md:text-sm">SOL</h4>
</div>
<div>
{#if $tokens.data?.nativeBalance.lamports}
<h4 class="font-semibold md:text-sm">
{(
$tokens.data?.nativeBalance.lamports /
LAMPORTS_PER_SOL
).toLocaleString()}
</h4>
{/if}

<h4 class="text-xs opacity-50">
{#if $sol.data}
{formatMoney(
($sol.data * $tokens.data?.nativeBalance.lamports) /
LAMPORTS_PER_SOL
)}
{/if}
</h4>
</div>
</div>
</a>

{#if $tokens.data}
{#each $tokens.data.items as token}
{#if token.token_info.decimals > 0 && token.id !== SOL}
<TokenProvider
{token}
status={{
isError: $tokens.isError,
isLoading: $tokens.isLoading,
}}
let:metadata
>
<a
class="mb-4 grid grid-cols-12 items-center gap-3 rounded-lg border px-3 py-2 hover:border-primary"
href="/token/{token.id}"
{#if $getTokensRequest}
{#each tokens as token}
{#if !isSol(token)}
{#if token.decimals > 0}
<TokenProvider
token={token.fullMetadata}
status={{
isError: $getTokensRequest.isError,
isLoading: $getTokensRequest.isLoading,
}}
let:metadata
>
<div class="col-span-2 p-1 md:col-span-1">
<!-- background so that if it doesn't load you dont' get ugly no image icons -->
<div
style="background-image: url('{metadata.image}')"
class="aspect-square w-full rounded-lg bg-cover"
/>
</div>
<div
class="col-span-10 flex items-center justify-between text-right md:col-span-11"
<a
class="mb-4 grid grid-cols-12 items-center gap-3 rounded-lg border px-3 py-2 hover:border-primary"
href="/token/{token.id}"
>
<div>
<h4 class="font-semibold md:text-sm">
{metadata?.name || ""}
</h4>
<div class="col-span-2 p-1 md:col-span-1">
<!-- background so that if it doesn't load you dont' get ugly no image icons -->
<div
style="background-image: url('{metadata.image}')"
class="aspect-square w-full rounded-lg bg-cover"
/>
</div>
<div>
<h4 class="font-semibold md:text-sm">
{(
token.token_info.balance /
10 ** token.token_info.decimals
).toLocaleString()}
</h4>
<h4 class="text-xs opacity-50">
{#if token.token_info.price_info}
{formatMoney(
(token.token_info?.price_info
?.price_per_token *
token.token_info.balance) /
10 ** token.token_info.decimals
)}
{/if}
</h4>
<div
class="col-span-10 flex items-center justify-between text-right md:col-span-11"
>
<div>
<h4 class="font-semibold md:text-sm">
{metadata?.name || ""}
</h4>
</div>
<div>
<h4 class="font-semibold md:text-sm">
{(
token.balance /
10 ** token.decimals
).toLocaleString()}
</h4>
<h4 class="text-xs opacity-50">
{#if token.price}
{formatMoney(token.balanceInUSD)}
{/if}
</h4>
</div>
</div>
</a>
</TokenProvider>
{/if}
{:else}
<a
class="mb-4 grid grid-cols-12 items-center gap-3 rounded-lg border px-3 py-2 hover:border-primary"
href="/token/{token.id}"
>
<div class="col-span-2 p-1 md:col-span-1">
<!-- background so that if it doesn't load you dont' get ugly no image icons -->
<div
style="background-image: url(/media/tokens/solana.png)"
class="aspect-square w-full rounded-lg bg-cover"
/>
</div>
<div
class="col-span-10 flex items-center justify-between text-right md:col-span-11"
>
<div>
<h4 class="font-semibold md:text-sm">SOL</h4>
</div>
</a>
</TokenProvider>
<div>
<h4 class="font-semibold md:text-sm">
{token.balance.toLocaleString()}
</h4>

<h4 class="text-xs opacity-50">
{formatMoney(token.balanceInUSD)}
</h4>
</div>
</div>
</a>
{/if}
{/each}
{:else}
Expand Down

0 comments on commit f17f3e9

Please sign in to comment.