diff --git a/app2/src/lib/components/Transfer/Assets.svelte b/app2/src/lib/components/Transfer/Assets.svelte
index c43872315c..0b086bbee1 100644
--- a/app2/src/lib/components/Transfer/Assets.svelte
+++ b/app2/src/lib/components/Transfer/Assets.svelte
@@ -13,8 +13,6 @@
function ensureTokensForChain() {
const chainId = transfer.sourceChain?.universal_chain_id;
if (!chainId) return;
-
- console.log(tokensStore.getData(chainId));
const tokenData = tokensStore.getData(chainId);
if (Option.isNone(tokenData)) {
tokensStore.fetchTokens(chainId);
@@ -102,13 +100,3 @@
{(transfer.baseToken?.representations[0]?.name ?? transfer.url.asset) || "Select asset"}
-
-
\ No newline at end of file
diff --git a/app2/src/lib/components/Transfer/index.svelte b/app2/src/lib/components/Transfer/index.svelte
index 74611686d8..37cec95182 100644
--- a/app2/src/lib/components/Transfer/index.svelte
+++ b/app2/src/lib/components/Transfer/index.svelte
@@ -10,6 +10,10 @@
const {transfer} = getTransfer()
+ $effect(() => {
+ console.log('ZKGM', transfer.ucs03address)
+ })
+
diff --git a/app2/src/lib/services/transfer-ucs03-evm/channel.ts b/app2/src/lib/services/transfer-ucs03-evm/channel.ts
new file mode 100644
index 0000000000..ac77bd033b
--- /dev/null
+++ b/app2/src/lib/services/transfer-ucs03-evm/channel.ts
@@ -0,0 +1,76 @@
+import {Effect} from "effect";
+import {Channel, Channels} from "$lib/schema/channel.ts";
+import {ChannelValidationError} from "$lib/services/transfer-ucs03-evm/errors.ts";
+
+export const getChannelInfoEffect = (
+ source_chain_id: string,
+ destination_chain_id: string,
+ channels: typeof Channels.Type
+): Effect.Effect =>
+ Effect.gen(function* () {
+ const rawChannel = channels.find(
+ chan =>
+ chan.source_chain_id === source_chain_id && chan.destination_chain_id === destination_chain_id
+ )
+
+ if (
+ !rawChannel ||
+ rawChannel.source_connection_id === null ||
+ rawChannel.source_channel_id === null ||
+ !rawChannel.source_port_id ||
+ rawChannel.destination_connection_id === null ||
+ rawChannel.destination_channel_id === null ||
+ !rawChannel.destination_port_id
+ ) {
+ return yield* Effect.fail(new ChannelValidationError({
+ source_chain_id,
+ destination_chain_id,
+ cause: 'Missing required channel information'
+ }))
+ }
+
+ return yield* Effect.try({
+ try: () => {
+ let source_port_id = String(rawChannel.source_port_id)
+ if (source_port_id.length < 4) {
+ throw new Error('source_port_id is too short')
+ }
+ source_port_id = source_port_id.slice(2)
+
+ let destination_port_id = String(rawChannel.destination_port_id)
+ if (destination_port_id.length < 4) {
+ throw new Error('destination_port_id is too short')
+ }
+ destination_port_id = destination_port_id.slice(2)
+
+ return new Channel({
+ source_chain_id,
+ source_connection_id: rawChannel.source_connection_id!,
+ source_channel_id: rawChannel.source_channel_id!,
+ source_port_id,
+ destination_chain_id,
+ destination_connection_id: rawChannel.destination_connection_id!,
+ destination_channel_id: rawChannel.destination_channel_id!,
+ destination_port_id
+ })
+ },
+ catch: err => new ChannelValidationError({
+ source_chain_id,
+ destination_chain_id,
+ cause: err
+ })
+ })
+ })
+
+// Safe synchronous wrapper function (similar to getDerivedReceiverSafe in your example)
+export const getChannelInfoSafe = (
+ source_chain_id: string,
+ destination_chain_id: string,
+ channels: typeof Channels.Type
+): typeof Channel.Type | null => {
+ const result = Effect.runSync(
+ Effect.either(getChannelInfoEffect(source_chain_id, destination_chain_id, channels))
+ )
+
+ return result._tag === 'Right' ? result.right : null
+}
\ No newline at end of file
diff --git a/app2/src/lib/services/transfer-ucs03-evm/channels.ts b/app2/src/lib/services/transfer-ucs03-evm/channels.ts
deleted file mode 100644
index bdee378904..0000000000
--- a/app2/src/lib/services/transfer-ucs03-evm/channels.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import type { FetchDecodeGraphqlError } from "$lib/utils/queries"
-import { Option } from "effect"
-import type { Chains } from "$lib/schema/chain"
-
-class ChainsStore {
- data: Option.Option = $state(Option.none())
- error: Option.Option = $state(Option.none())
-}
-
-export const chains = new ChainsStore()
diff --git a/app2/src/lib/services/transfer-ucs03-evm/errors.ts b/app2/src/lib/services/transfer-ucs03-evm/errors.ts
index 17bb7320e6..e2d003ad0e 100644
--- a/app2/src/lib/services/transfer-ucs03-evm/errors.ts
+++ b/app2/src/lib/services/transfer-ucs03-evm/errors.ts
@@ -49,4 +49,10 @@ export class AmountParsingError extends Data.TaggedError("AmountParsingError")<{
cause?: unknown | undefined
}> {}
+export class ChannelValidationError extends Data.TaggedError("ChannelValidationError")<{
+ source_chain_id: string
+ destination_chain_id: string
+ cause?: unknown | undefined
+}> {}
+
export type SubmitTransferError = WriteContractError | CreateWalletClientError
diff --git a/app2/src/lib/services/transfer-ucs03-evm/machine.ts b/app2/src/lib/services/transfer-ucs03-evm/machine.ts
index c583bbe03d..80b9c21e31 100644
--- a/app2/src/lib/services/transfer-ucs03-evm/machine.ts
+++ b/app2/src/lib/services/transfer-ucs03-evm/machine.ts
@@ -41,6 +41,7 @@ export async function nextState(
SwitchChain: ({ state }) => {
return SwitchChainState.$match(state, {
InProgress: async () => {
+ //@ts-ignore
const exit = await Effect.runPromiseExit(switchChain(params.sourceChain.id))
return TransferSubmission.SwitchChain({ state: SwitchChainState.Complete({ exit }) })
},
diff --git a/app2/src/lib/services/transfer-ucs03-evm/quoteToken.ts b/app2/src/lib/services/transfer-ucs03-evm/quoteToken.ts
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/app2/src/routes/transfer/transfer.svelte.ts b/app2/src/routes/transfer/transfer.svelte.ts
index daa4004974..968ac212cc 100644
--- a/app2/src/routes/transfer/transfer.svelte.ts
+++ b/app2/src/routes/transfer/transfer.svelte.ts
@@ -11,9 +11,9 @@ import {
} from "$lib/services/transfer-ucs03-evm";
import {chains} from "$lib/stores/chains.svelte.ts";
import {getChainFromWagmi} from "$lib/wallet/evm/index.ts";
-import type {Chain as ViemChain} from "viem";
-import {getChannelInfo} from "@unionlabs/client";
+import {type Chain as ViemChain, fromHex} from "viem";
import {channels} from "$lib/stores/channels.svelte.ts";
+import {getChannelInfoSafe} from "$lib/services/transfer-ucs03-evm/channel.ts";
export class Transfer {
isValid = $state(true);
@@ -45,25 +45,36 @@ export class Transfer {
return this.baseTokens.find((t: Token) => t.denom === this.url.asset) || null
});
- amount = $derived(this.url.amount);
parsedAmount = $derived.by(() => {
if (!this.baseToken) return null
- return getParsedAmountSafe(this.amount.toString(), this.baseToken)
+ return getParsedAmountSafe(this.url.amount.toString(), this.baseToken)
});
- receiver = $derived(this.url.receiver);
derivedReceiver = $derived.by(() => {
- return getDerivedReceiverSafe(this.receiver);
+ return getDerivedReceiverSafe(this.url.receiver);
+ });
+
+ channel = $derived.by(() => {
+ return Option.isSome(channels.data) && this.sourceChain && this.destinationChain
+ ? getChannelInfoSafe(this.sourceChain.chain_id, this.destinationChain.chain_id, channels.data.value)
+ : null;
+ });
+
+ ucs03address = $derived.by(() => {
+ if (!this.sourceChain || !this.channel?.source_port_id) {
+ return null;
+ }
+ return this.sourceChain.rpc_type === "cosmos"
+ ? fromHex(`0x${this.channel.source_port_id}`, "string")
+ : `0x${this.channel.source_port_id}`;
});
- channel = $derived(getChannelInfo(this.sourceChain.chain_id, this.destinationChain.chain_id, channels.data))
- ucs03address = $state()
quoteToken = $state()
wethQuoteToken = $state()
args = $derived({
sourceChain: getChainFromWagmi(Number(this.sourceChain?.chain_id)) as ViemChain,
- sourceChannelId: 9,
+ sourceChannelId: this.channel?.source_channel_id,
ucs03address: "0x84f074c15513f15baea0fbed3ec42f0bd1fb3efa",
baseToken: this.baseToken?.denom,
baseAmount: this.parsedAmount,
@@ -86,7 +97,6 @@ export class Transfer {
}
}
-
const STATE_KEY = Symbol("TRANSFER");
export interface RawTransfer {