Skip to content

Commit e91e850

Browse files
authored
feat(app2): transfer fixes for demo (#4149)
2 parents f5e04cc + c95fb38 commit e91e850

23 files changed

+348
-210
lines changed

app2/src/lib/components/Transfer/ChainAsset/TransferAsset.svelte

-3
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ let displayAmount = $derived.by(() => {
3737
})
3838
3939
let isLoading = $derived(Option.isSome(transfer.sortedBalances) && Option.isNone(tokenBalance))
40-
$effect(() => {
41-
console.log(token)
42-
})
4340
4441
export const toDisplayName = (
4542
chain_id: string | undefined | null,

app2/src/lib/components/Transfer/index.svelte

+66-74
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,13 @@ import {
3636
} from "@unionlabs/sdk/cosmos"
3737
import { fromHex, http, isHex } from "viem"
3838
import { truncate } from "$lib/utils/format.ts"
39-
import {
40-
ApprovalRequired,
41-
Filling,
42-
getStepDescription,
43-
SubmitInstruction,
44-
type TransferStep,
45-
WaitForIndex
46-
} from "./transfer-step.ts"
39+
import * as TransferStep from "./transfer-step.ts"
4740
import { isValidBech32ContractAddress } from "@unionlabs/client"
4841
import IndexPage from "$lib/components/Transfer/pages/IndexPage.svelte"
4942
5043
let showDetails = $state(false)
5144
let currentPage = $state(0)
52-
let instruction: Option.Option<Instruction> = $state(Option.none())
45+
let instruction: Option.Option<Instruction.Instruction> = $state(Option.none())
5346
let allowances: Option.Option<Array<{ token: string; allowance: bigint }>> = $state(Option.none())
5447
5548
//This should now handle cosmos, evm and aptos (when aptos is implemented)
@@ -90,7 +83,7 @@ let transferIntents = $derived.by(() => {
9083
return Option.some([
9184
{
9285
sender: sender.value,
93-
receiver: transferValue.receiver,
86+
receiver: transferValue.receiver.toLowerCase(),
9487
baseToken: isHex(transferValue.baseToken)
9588
? fromHex(transferValue.baseToken, "string")
9689
: transferValue.baseToken,
@@ -108,7 +101,8 @@ let requiredApprovals = $derived.by(() => {
108101
const requiredAmounts = new Map<string, bigint>()
109102
for (const intent of transferIntents.value) {
110103
const currentAmount = requiredAmounts.get(intent.baseToken) || 0n
111-
requiredAmounts.set(intent.baseToken, intent.baseAmount)
104+
// FIX: Add the new amount to the current amount instead of replacing it
105+
requiredAmounts.set(intent.baseToken, currentAmount + intent.baseAmount)
112106
}
113107
114108
// Filter for tokens that need approval (allowance < required amount)
@@ -127,7 +121,7 @@ let requiredApprovals = $derived.by(() => {
127121
128122
// Derive the steps based on required approvals and instruction
129123
let transferSteps = $derived.by(() => {
130-
const steps: Array<TransferStep> = [Filling()]
124+
const steps: Array<TransferStep.TransferStep> = [TransferStep.Filling()]
131125
132126
// Add approval steps if needed
133127
if (Option.isSome(requiredApprovals)) {
@@ -137,7 +131,7 @@ let transferSteps = $derived.by(() => {
137131
const tokenAllowance = allowances.value.find(a => a.token === approval.token)
138132
if (tokenAllowance) {
139133
steps.push(
140-
ApprovalRequired({
134+
TransferStep.ApprovalRequired({
141135
token: approval.token,
142136
requiredAmount: approval.requiredAmount,
143137
currentAllowance: tokenAllowance.allowance
@@ -150,8 +144,8 @@ let transferSteps = $derived.by(() => {
150144
151145
// Add the instruction submission step if we have an instruction
152146
if (Option.isSome(instruction)) {
153-
steps.push(SubmitInstruction({ instruction: instruction.value }))
154-
steps.push(WaitForIndex())
147+
steps.push(TransferStep.SubmitInstruction({ instruction: instruction.value }))
148+
steps.push(TransferStep.WaitForIndex())
155149
}
156150
157151
return steps.length > 0 ? Option.some(steps) : Option.none()
@@ -218,8 +212,7 @@ const intentsToBatch = (ti: typeof transferIntents) =>
218212
const provideCosmWasmClientSource = Effect.provideServiceEffect(
219213
CosmWasmClientSource,
220214
pipe(
221-
Option.some("https://rpc.rpc-node.union-testnet-10.union.build"),
222-
// transfer.sourceChain.value.getRpcUrl("rpc"),
215+
transfer.sourceChain.value.getRpcUrl("rpc"),
223216
Option.map(createCosmWasmClient),
224217
Effect.flatten,
225218
Effect.map(client => ({ client }))
@@ -229,8 +222,7 @@ const intentsToBatch = (ti: typeof transferIntents) =>
229222
const provideCosmWasmClientDestination = Effect.provideServiceEffect(
230223
CosmWasmClientDestination,
231224
pipe(
232-
Option.some("https://rpc.rpc-node.union-testnet-10.union.build"),
233-
//transfer.destinationChain.value.getRpcUrl("rpc"),
225+
transfer.destinationChain.value.getRpcUrl("rpc"),
234226
Option.map(createCosmWasmClient),
235227
Effect.flatten,
236228
Effect.map(client => ({ client }))
@@ -308,7 +300,7 @@ const intentsToBatch = (ti: typeof transferIntents) =>
308300
Effect.sync(() => console.log("batch: Cosmos->EVM order created", order))
309301
),
310302
Effect.catchAll(error => {
311-
console.error("batch: Error creating Cosmos->EVM order", error.cause)
303+
console.error("batch: Error creating Cosmos->EVM order", error)
312304
return Effect.fail(error)
313305
}),
314306
provideCosmWasmClientSource,
@@ -339,7 +331,9 @@ const intentsToBatch = (ti: typeof transferIntents) =>
339331
340332
// Handle both array and single order cases
341333
console.log(`batch: Orders created:`, orders)
342-
const batch = Array.isArray(orders) ? Batch(orders) : Batch([orders])
334+
const batch = new Batch({
335+
operand: Array.isArray(orders) ? orders : [orders]
336+
})
343337
console.log(`batch: Batch created:`, batch)
344338
return batch
345339
}).pipe(
@@ -410,9 +404,7 @@ const checkAllowances = (ti: typeof transferIntents) =>
410404
// For Cosmos chains use a CosmWasm client to query CW20 allowances.
411405
const rpcUrl = sourceChain.getRpcUrl("rpc")
412406
if (Option.isNone(rpcUrl)) return Option.none()
413-
const cosmwasmClient = yield* createCosmWasmClient(
414-
"https://rpc.rpc-node.union-testnet-10.union.build"
415-
)
407+
const cosmwasmClient = yield* createCosmWasmClient(rpcUrl)
416408
417409
// Query each token (assumed to be a CW20 contract) for the allowance.
418410
const allowanceChecks = yield* Effect.all(
@@ -421,7 +413,6 @@ const checkAllowances = (ti: typeof transferIntents) =>
421413
const decodedAddr = fromHex(tokenAddress, "string")
422414
423415
if (!isValidBech32ContractAddress(decodedAddr)) {
424-
console.log("It's native token, returning none. Token:", tokenAddress)
425416
return Option.none()
426417
}
427418
@@ -491,33 +482,33 @@ let actionButtonText = $derived.by(() => {
491482
return "Complete"
492483
}
493484
494-
if (currentStep._tag === "Filling") {
495-
return "Continue"
496-
}
497-
498-
if (currentStep._tag === "ApprovalRequired") {
499-
return "Approve"
500-
}
501-
502-
if (currentStep._tag === "SubmitInstruction") {
503-
return "Submit"
504-
}
505-
506-
return "Next"
485+
return TransferStep.match(currentStep, {
486+
Filling: () => "Continue",
487+
ApprovalRequired: () => "Approve",
488+
SubmitInstruction: () => "Submit",
489+
WaitForIndex: () => "Submit"
490+
})
507491
})
508492
509493
function handleActionButtonClick() {
510494
if (Option.isNone(transferSteps)) return
511495
496+
console.log("handleActionButtonClick called", {
497+
transferSteps: transferSteps,
498+
currentPage: currentPage
499+
})
500+
512501
const currentStep = transferSteps.value[currentPage]
513502
514-
if (currentStep._tag === "Filling") {
503+
if (TransferStep.is("Filling")(currentStep)) {
515504
// Lock the transfer values before proceeding
516505
if (Option.isNone(lockedTransferStore.get())) {
517506
const newLockedTransfer = LockedTransfer.fromTransfer(
518507
transfer.sourceChain,
519508
transfer.destinationChain,
520509
transfer.channel,
510+
transfer.parsedAmount,
511+
transfer.baseToken,
521512
transferSteps
522513
)
523514
@@ -532,27 +523,27 @@ function handleActionButtonClick() {
532523
return
533524
}
534525
535-
if (currentStep._tag === "ApprovalRequired") {
526+
if (TransferStep.is("ApprovalRequired")(currentStep)) {
536527
goToNextPage()
537528
return
538529
}
539530
540-
if (currentStep._tag === "SubmitInstruction") {
531+
if (TransferStep.is("SubmitInstruction")(currentStep)) {
541532
goToNextPage()
542533
return
543534
}
544535
}
545536
</script>
546537

547538
<Card
548-
divided
549-
class="w-sm my-24 relative self-center flex flex-col justify-between min-h-[450px] overflow-hidden"
539+
divided
540+
class="w-sm my-24 relative self-center flex flex-col justify-between min-h-[450px] overflow-hidden"
550541
>
551542
<div class="p-4 w-full">
552543
<StepProgressBar
553-
class="w-full"
554-
currentStep={currentPage + 1}
555-
totalSteps={lockedTransferStore.get().pipe(
544+
class="w-full"
545+
currentStep={currentPage + 1}
546+
totalSteps={lockedTransferStore.get().pipe(
556547
Option.map((lts) => lts.steps.length),
557548
Option.getOrElse(() =>
558549
transferSteps.pipe(
@@ -561,10 +552,12 @@ function handleActionButtonClick() {
561552
),
562553
),
563554
)}
564-
stepDescriptions={lockedTransferStore.get().pipe(
565-
Option.map((lts) => lts.steps.map(getStepDescription)),
555+
stepDescriptions={lockedTransferStore.get().pipe(
556+
Option.map((lts) => lts.steps.map(TransferStep.description)),
566557
Option.orElse(() =>
567-
transferSteps.pipe(Option.map((ts) => ts.map(getStepDescription))),
558+
transferSteps.pipe(
559+
Option.map((ts) => ts.map(TransferStep.description)),
560+
),
568561
),
569562
Option.getOrElse(() => ["Configure your transfer"]),
570563
)}
@@ -575,34 +568,33 @@ function handleActionButtonClick() {
575568
<div class="relative flex-1 overflow-hidden">
576569
<!-- Pages wrapper with horizontal sliding -->
577570
<div
578-
class="absolute inset-0 flex transition-transform duration-300 ease-in-out"
579-
style="transform: translateX(-{currentPage * 100}%);"
571+
class="absolute inset-0 flex transition-transform duration-300 ease-in-out"
572+
style="transform: translateX(-{currentPage * 100}%);"
580573
>
581574
<!-- Page 1: Filling -->
582-
<FillingPage onContinue={handleActionButtonClick} {actionButtonText}/>
575+
<FillingPage onContinue={handleActionButtonClick} {actionButtonText} />
583576

584577
<!-- Dynamic pages for each step -->
585578
{#if Option.isSome(lockedTransferStore.get())}
586579
{#each lockedTransferStore.get().value.steps.slice(1) as step, i}
587-
{#if step._tag === "ApprovalRequired"}
580+
{#if TransferStep.is("ApprovalRequired")(step)}
588581
<ApprovalPage
589-
stepIndex={i + 1}
590-
onBack={goToPreviousPage}
591-
onApprove={handleActionButtonClick}
592-
{actionButtonText}
582+
stepIndex={i + 1}
583+
onBack={goToPreviousPage}
584+
onApprove={handleActionButtonClick}
585+
{actionButtonText}
593586
/>
594-
{:else if step._tag === "SubmitInstruction"}
587+
{:else if TransferStep.is("SubmitInstruction")(step)}
595588
<SubmitPage
596-
stepIndex={i + 1}
597-
onBack={goToPreviousPage}
598-
onSubmit={handleActionButtonClick}
599-
{actionButtonText}
589+
stepIndex={i + 1}
590+
onBack={goToPreviousPage}
591+
onSubmit={handleActionButtonClick}
592+
{actionButtonText}
600593
/>
601-
{:else if step._tag === "WaitForIndex"}
594+
{:else if TransferStep.is("WaitForIndex")(step)}
602595
<IndexPage
603-
stepIndex={i + 1}
604-
onBack={goToPreviousPage}
605-
{actionButtonText}
596+
stepIndex={i + 1}
597+
onBack={goToPreviousPage}
606598
/>
607599
{/if}
608600
{/each}
@@ -611,7 +603,7 @@ function handleActionButtonClick() {
611603
</div>
612604

613605
{#if showDetails}
614-
<ShowData/>
606+
<ShowData />
615607
{/if}
616608
</Card>
617609

@@ -623,22 +615,22 @@ function handleActionButtonClick() {
623615
<ol class="list-decimal pl-5 mt-2">
624616
{#each lockedTransferStore
625617
.get()
626-
.pipe(Option.map((lts) => lts.steps), Option.orElse(() => transferSteps), Option.getOrElse(() => [],),) as step, index}
618+
.pipe( Option.map((lts) => lts.steps), Option.orElse(() => transferSteps), Option.getOrElse( () => [], ), ) as step, index}
627619
<li class="mb-2" class:font-bold={index === currentPage}>
628-
{#if step._tag === "Filling"}
620+
{#if TransferStep.is("Filling")(step)}
629621
<div>Configure transfer details</div>
630-
{:else if step._tag === "ApprovalRequired"}
622+
{:else if TransferStep.is("ApprovalRequired")(step)}
631623
<div>
632624
Approve token: <span class="font-mono"
633-
>{truncate(step.token, 8, "middle")}</span
634-
>
625+
>{truncate(step.token, 8, "middle")}</span
626+
>
635627
<div class="text-sm">
636628
Current allowance: {step.currentAllowance.toString()}
637-
<br/>
629+
<br />
638630
Required amount: {step.requiredAmount.toString()}
639631
</div>
640632
</div>
641-
{:else if step._tag === "SubmitInstruction"}
633+
{:else if TransferStep.is("SubmitInstruction")(step)}
642634
<div>Submit transfer instruction</div>
643635
{/if}
644636
</li>

app2/src/lib/components/Transfer/locked-transfer.ts

+17-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Option } from "effect"
2-
import type { Chain, Channel } from "@unionlabs/sdk/schema"
2+
import type { Chain, Channel, Token } from "@unionlabs/sdk/schema"
33
import type { TransferStep } from "./transfer-step.ts"
44

55
/**
@@ -10,17 +10,23 @@ export class LockedTransfer {
1010
sourceChain: Chain
1111
destinationChain: Chain
1212
channel: Channel
13+
parsedAmount: string
14+
baseToken: Token
1315
steps: Array<TransferStep>
1416

1517
constructor(
1618
sourceChain: Chain,
1719
destinationChain: Chain,
1820
channel: Channel,
21+
parsedAmount: string,
22+
baseToken: Token,
1923
steps: Array<TransferStep>
2024
) {
2125
this.sourceChain = sourceChain
2226
this.destinationChain = destinationChain
2327
this.channel = channel
28+
this.parsedAmount = parsedAmount
29+
this.baseToken = baseToken
2430
this.steps = steps
2531
}
2632

@@ -32,11 +38,18 @@ export class LockedTransfer {
3238
sourceChain: Option.Option<Chain>,
3339
destinationChain: Option.Option<Chain>,
3440
channel: Option.Option<Channel>,
41+
parsedAmount: Option.Option<string>,
42+
baseToken: Option.Option<Token>,
3543
steps: Option.Option<Array<TransferStep>>
3644
): Option.Option<LockedTransfer> {
37-
return Option.all([sourceChain, destinationChain, channel, steps]).pipe(
38-
Option.map(([sc, dc, ch, st]) => new LockedTransfer(sc, dc, ch, st))
39-
)
45+
return Option.all([
46+
sourceChain,
47+
destinationChain,
48+
channel,
49+
parsedAmount,
50+
baseToken,
51+
steps
52+
]).pipe(Option.map(([sc, dc, ch, pa, bt, st]) => new LockedTransfer(sc, dc, ch, pa, bt, st)))
4053
}
4154

4255
/**

0 commit comments

Comments
 (0)