Skip to content

Commit 44a10fb

Browse files
committed
feat(app): add rewards and dust
1 parent 3ad75f6 commit 44a10fb

File tree

3 files changed

+691
-9
lines changed

3 files changed

+691
-9
lines changed

app2/src/lib/components/stake/BalanceCard.svelte

Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,18 @@
22
import Button from "$lib/components/ui/Button.svelte"
33
import Card from "$lib/components/ui/Card.svelte"
44
import Tabs from "$lib/components/ui/Tabs.svelte"
5+
import { runPromiseExit$ } from "$lib/runtime"
6+
import { DESTINATION_CHANNEL_ID } from "$lib/stake/config"
7+
import { predictProxy } from "$lib/stake/instantiate2"
8+
import { wallets as WalletStore } from "$lib/stores/wallets.svelte"
59
import { Utils } from "@unionlabs/sdk"
10+
import { Cosmos } from "@unionlabs/sdk-cosmos"
11+
import { EU_LST } from "@unionlabs/sdk/Constants"
612
import type { Chain, Token } from "@unionlabs/sdk/schema"
7-
import { BigDecimal, pipe } from "effect"
13+
import { Array, BigDecimal, Effect, Exit, pipe } from "effect"
814
import * as O from "effect/Option"
15+
import ProxyDustRecovery from "./ProxyDustRecovery.svelte"
16+
import StakingRewardsDisplay from "./StakingRewardsDisplay.svelte"
917
import TokenBalanceRow from "./TokenBalanceRow.svelte"
1018
1119
interface Props {
@@ -15,6 +23,8 @@ interface Props {
1523
uOnEvmBalance: O.Option<bigint>
1624
eUOnEvmBalance: O.Option<bigint>
1725
purchaseRate: O.Option<BigDecimal.BigDecimal>
26+
redemptionRate: O.Option<BigDecimal.BigDecimal>
27+
stakingHistory?: O.Option<Array.NonEmptyReadonlyArray<any>>
1828
}
1929
2030
let {
@@ -24,6 +34,8 @@ let {
2434
uOnEvmBalance,
2535
eUOnEvmBalance,
2636
purchaseRate,
37+
redemptionRate,
38+
stakingHistory = O.none(),
2739
}: Props = $props()
2840
2941
// Calculate eU value of U balance
@@ -53,25 +65,75 @@ const eUBalanceInU = $derived<O.Option<BigDecimal.BigDecimal>>(
5365
),
5466
)
5567
56-
type BalanceTab = "balances" | "rewards"
68+
type BalanceTab = "balances" | "rewards" | "dust"
5769
let selectedTab = $state<BalanceTab>("balances")
70+
71+
// Query proxy balance for dust
72+
const proxyDustData = runPromiseExit$(() => {
73+
void WalletStore.evmAddress
74+
75+
return pipe(
76+
WalletStore.evmAddress,
77+
O.match({
78+
onNone: () => Effect.succeed({ euDust: BigDecimal.make(0n, 18), proxyAddress: "" }),
79+
onSome: (address) =>
80+
Effect.gen(function*() {
81+
const proxy = yield* predictProxy({
82+
path: 0n,
83+
channel: DESTINATION_CHANNEL_ID,
84+
sender: address,
85+
})
86+
87+
// Query eU balance on proxy
88+
const euBalanceResponse = yield* pipe(
89+
Cosmos.queryContract(EU_LST, {
90+
balance: { address: proxy.address },
91+
}),
92+
Effect.map(resp => resp as { balance: string }),
93+
Effect.catchAll(() => Effect.succeed({ balance: "0" })),
94+
)
95+
96+
// Convert the raw balance string (with 18 decimals) to BigDecimal
97+
const euDustRaw = BigInt(euBalanceResponse.balance)
98+
const euDust = BigDecimal.make(euDustRaw, 18) // 18 decimals for eU
99+
100+
return { euDust, proxyAddress: proxy.address }
101+
}),
102+
}),
103+
Effect.provide(Cosmos.Client.Live("https://rpc.union.build")),
104+
Effect.catchAll(() => Effect.succeed({ euDust: BigDecimal.make(0n, 18), proxyAddress: "" })),
105+
)
106+
})
107+
108+
const proxyEuDust = $derived(
109+
O.isSome(proxyDustData.current) && Exit.isSuccess(proxyDustData.current.value)
110+
? O.some(proxyDustData.current.value.value.euDust)
111+
: O.none(),
112+
)
113+
114+
const proxyAddress = $derived(
115+
O.isSome(proxyDustData.current) && Exit.isSuccess(proxyDustData.current.value)
116+
? O.some(proxyDustData.current.value.value.proxyAddress)
117+
: O.none(),
118+
)
58119
</script>
59120

60121
<Card divided>
61122
<div class="px-4 py-2.5 border-b border-zinc-800">
62123
<Tabs
63124
items={[
64125
{ id: "balances", label: "Balances" },
65-
// { id: "rewards", label: "Rewards" },
126+
{ id: "rewards", label: "Rewards" },
127+
{ id: "dust", label: "Dust" },
66128
]}
67129
activeId={selectedTab}
68130
onTabChange={(id) => selectedTab = id as BalanceTab}
69131
/>
70132
</div>
71133

72-
<div class="p-4">
134+
<div class="p-4 min-h-[250px] flex flex-col">
73135
{#if selectedTab === "balances"}
74-
<div class="flex flex-col gap-3">
136+
<div class="flex flex-col gap-3 flex-1">
75137
<!-- U Balance Card -->
76138
<TokenBalanceRow
77139
chain={evmChain}
@@ -115,18 +177,35 @@ let selectedTab = $state<BalanceTab>("balances")
115177
)}
116178
/>
117179

180+
<div class="flex-1"></div>
181+
118182
<!-- Transfer U Button -->
119183
<Button
120184
variant="primary"
121185
href="/transfer?source=union-1&destination=1&asset=0x6175"
122-
class="w-full h-9 text-sm font-semibold mt-1"
186+
class="w-full"
123187
>
124188
Transfer U →
125189
</Button>
126190
</div>
127-
{:else}
128-
<div class="text-center py-8 text-zinc-500">
129-
Rewards coming soon...
191+
{:else if selectedTab === "rewards"}
192+
<div class="flex-1">
193+
<StakingRewardsDisplay
194+
eUBalance={eUOnEvmBalance}
195+
{redemptionRate}
196+
{stakingHistory}
197+
{proxyEuDust}
198+
/>
199+
</div>
200+
{:else if selectedTab === "dust"}
201+
<div class="flex-1">
202+
<ProxyDustRecovery
203+
{evmChain}
204+
{eUOnEvmToken}
205+
{redemptionRate}
206+
{proxyEuDust}
207+
{proxyAddress}
208+
/>
130209
</div>
131210
{/if}
132211
</div>

0 commit comments

Comments
 (0)