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 {