Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transfer args #3920

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
75 changes: 75 additions & 0 deletions app2/src/lib/examples/transfer-arguments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
type EVMTransferInput = {
type: "evm"
baseToken: string
baseAmount: string
quoteToken: string
quoteAmount: string
sourceChannelId: number
wethToken: string
receiver: string
ucs03address: string
}

type CosmosTransferInput = {
type: "cosmos"
baseToken: string
baseAmount: string
quoteToken: string
quoteAmount: string
sourceChannelId: number
wethToken: null
receiver: string
ucs03address: string
}

type AptosTransferInput = {
type: "aptos"
baseToken: string
baseAmount: string
quoteToken: string
quoteAmount: string
sourceChannelId: number
wethToken: null
receiver: string
ucs03address: string
}

export const examples: {
evm: EVMTransferInput
cosmos: CosmosTransferInput
aptos: AptosTransferInput
} = {
evm: {
type: "evm",
baseToken: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
baseAmount: "1000000000000000000",
quoteToken: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
quoteAmount: "1000000",
receiver: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
sourceChannelId: 1,
ucs03address: "0x742d35cc6634c0532925a3b844bc454e4438f44e",
wethToken: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
},
cosmos: {
type: "cosmos",
baseToken: "0x1234567890abcdef1234567890abcdef12345678",
baseAmount: "10000000",
quoteToken: "0xabcdef1234567890abcdef1234567890abcdef12",
quoteAmount: "10000000",
receiver: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
sourceChannelId: 2,
ucs03address: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", // Hex, 32 bytes
wethToken: null
},
aptos: {
type: "aptos",
baseToken: "0x1abcdef1234567890abcdef1234567890abcdef12",
baseAmount: "1000000000000000000",
quoteToken: "0x2abcdef1234567890abcdef1234567890abcdef12",
quoteAmount: "10000000",
receiver: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
sourceChannelId: 3,
ucs03address: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
wethToken: null
}
}
2 changes: 1 addition & 1 deletion app2/src/lib/schema/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const RpcType = Schema.Union(
Schema.Literal("evm"),
Schema.Literal("cosmos"),
Schema.Literal("aptos")
)
).annotations({ message: () => "type must be 'evm', 'cosmos', or 'aptos'" })

export class ChainFeatures extends Schema.Class<ChainFeatures>("ChainFeatures")({
channel_list: Schema.Boolean,
Expand Down
5 changes: 4 additions & 1 deletion app2/src/lib/schema/channel.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { Schema } from "effect"

export const ChannelId = Schema.Int.pipe(Schema.brand("ChannelId"))
export const ChannelId = Schema.Int.pipe(
Schema.nonNegative({ message: () => "sourceChannelId must be non-negative" }),
Schema.brand("ChannelId")
)
7 changes: 7 additions & 0 deletions app2/src/lib/schema/token.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { Schema } from "effect"
import { Hex } from "$lib/schema/hex"
import { AddressEvmCanonical } from "$lib/schema/address"

export const TokenRawDenom = Hex.pipe(Schema.brand("TokenRawDenom"))
export const TokenRawAmount = Schema.BigInt.pipe(Schema.brand("TokenRawAmount"))
export const EVMWethToken = AddressEvmCanonical.pipe(
Schema.annotations({
message: () =>
"WETH token must be a valid EVM canonical address (e.g., 0x followed by 40 hex chars)"
})
)
103 changes: 103 additions & 0 deletions app2/src/lib/schema/transfer-arguments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Schema } from "effect"
import {
AddressAptosCanonical,
AddressCosmosCanonical,
AddressEvmCanonical
} from "$lib/schema/address"
import { RpcType } from "$lib/schema/chain"
import { EVMWethToken, TokenRawAmount, TokenRawDenom } from "$lib/schema/token"
import { ChannelId } from "$lib/schema/channel"

const CommonTransferFields = {
baseToken: TokenRawDenom.annotations({
message: () => "baseToken must be a non-empty string (e.g., token address or symbol)"
}),
baseAmount: TokenRawAmount.annotations({
message: () => "baseAmount must be a valid bigint string (e.g., '1000000')"
}),
quoteToken: TokenRawDenom.annotations({
message: () => "quoteToken must be a non-empty string (e.g., token address or symbol)"
}),
quoteAmount: TokenRawAmount.annotations({
message: () => "quoteAmount must be a valid bigint string (e.g., '1000000')"
}),
sourceChannelId: ChannelId.annotations({
message: () => "sourceChannelId must be a non-negative integer"
})
}

export class EVMTransfer extends Schema.Class<EVMTransfer>("EVMTransfer")({
type: RpcType.pipe(
Schema.filter(v => v === "evm"),
Schema.annotations({ message: () => "type must be 'evm'" })
),
...CommonTransferFields,
wethToken: EVMWethToken,
receiver: AddressEvmCanonical.pipe(
Schema.annotations({
message: () =>
"receiver must be a valid EVM canonical address (e.g., 0x followed by 40 hex chars)"
})
),
ucs03address: AddressEvmCanonical.pipe(
Schema.annotations({
message: () =>
"ucs03address must be a valid EVM Zkgm address (e.g., 0x followed by 40 hex chars)"
})
)
}) {}

export class CosmosTransfer extends Schema.Class<CosmosTransfer>("CosmosTransfer")({
type: RpcType.pipe(
Schema.filter(v => v === "cosmos"),
Schema.annotations({ message: () => "type must be 'cosmos'" })
),
...CommonTransferFields,
wethToken: Schema.Null,
receiver: AddressCosmosCanonical.pipe(
Schema.annotations({
message: () =>
"receiver must be a valid Cosmos canonical address (e.g., 0x followed by 40 or 64 hex chars)"
})
),
ucs03address: AddressCosmosCanonical.pipe(
// Changed to hex
Schema.annotations({
message: () =>
"ucs03address must be a valid Cosmos Zkgm address in hex (e.g., 0x followed by 40 or 64 hex chars)"
})
)
}) {}

export class AptosTransfer extends Schema.Class<AptosTransfer>("AptosTransfer")({
type: RpcType.pipe(
Schema.filter(v => v === "aptos"),
Schema.annotations({ message: () => "type must be 'aptos'" })
),
...CommonTransferFields,
wethToken: Schema.Null,
receiver: AddressAptosCanonical.pipe(
Schema.annotations({
message: () =>
"receiver must be a valid Aptos canonical address (e.g., 0x followed by 64 hex chars)"
})
),
ucs03address: AddressAptosCanonical.pipe(
Schema.annotations({
message: () =>
"ucs03address must be a valid Aptos Zkgm address (e.g., 0x followed by 64 hex chars)"
})
)
}) {}

export const TransferSchema = Schema.Union(EVMTransfer, CosmosTransfer, AptosTransfer).annotations({
identifier: "Transfer",
title: "Transfer",
description: "transfer arguments"
})

export type Transfer = Schema.Schema.Type<typeof TransferSchema>

export type EVMTransferType = Schema.Schema.Type<typeof EVMTransfer>
export type CosmosTransferType = Schema.Schema.Type<typeof CosmosTransfer>
export type AptosTransferType = Schema.Schema.Type<typeof AptosTransfer>
72 changes: 72 additions & 0 deletions app2/src/routes/transfer/validate/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!-- src/routes/+page.svelte -->
<script lang="ts">
import { Effect, Schema } from "effect"
import type { RpcType } from "$lib/schema/chain"
import {
AptosTransfer,
CosmosTransfer,
EVMTransfer,
type Transfer
} from "$lib/schema/transfer-arguments"
import { examples } from "$lib/examples/transfer-arguments"

type RpcTypeValue = Schema.Schema.Type<typeof RpcType>

let results: Array<{ type: string; data?: Transfer | undefined; error?: string | undefined }> = []

function handleResult(type: RpcTypeValue, parsed: Transfer | undefined, error: unknown) {
if (parsed) {
console.log(`${type} example:`, parsed)
results = [...results, { type, data: parsed, error: undefined }]
} else {
console.error(`${type} example failed:`, error)
results = [...results, { type, error: String(error), data: undefined }]
}
}

function validateEvm() {
const effect = Schema.decode(EVMTransfer)(examples.evm)
Effect.runPromise(effect)
.then(parsed => handleResult("evm", parsed, undefined))
.catch(error => handleResult("evm", undefined, error))
}

function validateCosmos() {
const effect = Schema.decode(CosmosTransfer)(examples.cosmos)
Effect.runPromise(effect)
.then(parsed => handleResult("cosmos", parsed, undefined))
.catch(error => handleResult("cosmos", undefined, error))
}

function validateAptos() {
const effect = Schema.decode(AptosTransfer)(examples.aptos)
Effect.runPromise(effect)
.then(parsed => handleResult("aptos", parsed, undefined))
.catch(error => handleResult("aptos", undefined, error))
}
</script>

<main class="p-8 max-w-5xl mx-auto bg-zinc-950 min-h-screen">
<h1 class="text-4xl font-bold text-zinc-100 mb-4 text-center">Transfer Schema Validation</h1>
<p class="text-lg text-zinc-400 mb-8 text-center">Check the console for detailed logs of the examples.</p>

<div class="grid gap-6 mb-8">
{#each results as result}
<div class="bg-zinc-800 rounded-lg p-6 shadow-md border border-zinc-700">
<h2 class="text-2xl font-semibold text-zinc-200 mb-4">{result.type.toUpperCase()} Example</h2>
{#if result.data}
<p class="text-green-400 font-bold mb-4">Success!</p>
<pre class="bg-zinc-900 text-zinc-700 p-4 rounded-md text-sm font-mono overflow-x-auto whitespace-pre-wrap border border-zinc-600">{JSON.stringify(result.data, (_, v) => typeof v === "bigint" ? v.toString() : v, 2)}</pre>
{:else if result.error}
<p class="text-red-400 font-bold mb-4 break-words">Error: {result.error}</p>
{/if}
</div>
{/each}
</div>

<div class="flex justify-center gap-4 flex-wrap">
<button on:click={validateEvm} class="bg-zinc-700 text-zinc-100 px-6 py-3 rounded-md text-base font-medium hover:bg-zinc-600 active:bg-zinc-800 transition duration-200 hover:-translate-y-1 active:translate-y-0">Validate EVM Example</button>
<button on:click={validateCosmos} class="bg-zinc-700 text-zinc-100 px-6 py-3 rounded-md text-base font-medium hover:bg-zinc-600 active:bg-zinc-800 transition duration-200 hover:-translate-y-1 active:translate-y-0">Validate Cosmos Example</button>
<button on:click={validateAptos} class="bg-zinc-700 text-zinc-100 px-6 py-3 rounded-md text-base font-medium hover:bg-zinc-600 active:bg-zinc-800 transition duration-200 hover:-translate-y-1 active:translate-y-0">Validate Aptos Example</button>
</div>
</main>