Send Funds Union → Sepolia
This guide walks you through writing our example “Send Funds Union -> Sepolia”. The goal of this guide it to show you how to create a token order and submit it to the ucs03-zkgm interface.
Relevant imports will be included with each step. Outside of libraries provided by Union, this guide uses Effect.
This first section is a walk through of creating the program section of the send funds example.
Begin by using Effect to create a program function.
import { Effect, Logger } from "effect"
const program = Effect.gen(function*() {})
Using the ChainRegistry
from the Union TS SDK, you can declare the source and destination chains used in this example. In this case, the source is Union Testnet (union.union-testnet-10
) and the destination is Sepolia (ethereum.11155111
).
import { ChainRegistry } from "@unionlabs/sdk/ChainRegistry"import { UniversalChainId } from "@unionlabs/sdk/schema/chain"import { Effect, Logger } from "effect"
const program = Effect.gen(function*() { const source = yield* ChainRegistry.byUniversalId( UniversalChainId.make("union.union-testnet-10"), ) const destination = yield* ChainRegistry.byUniversalId( UniversalChainId.make("ethereum.11155111"), )})
Now you can define the token order that will be responsible for the transfer. This example uses the TokenOrderV2
TS interface.
To construct the token order, you will need the token contract/denom on both the source chain (baseToken
) and the destination chain (quoteToken
). In this case, we are using the relevant denom and contract address for U.
We also need to determine the Kind
for the TokenOrder
. In this case, we use solve
. Though kind can be initialize
, escrow
, unescrow
, or solve
. To understand which kind of token order to use, refer to the ucs03 EVM Token Order Examples docs.
import { TokenOrder, ZkgmClient, ZkgmClientRequest, ZkgmClientResponse } from "@unionlabs/sdk"import { Effect, Logger } from "effect"
const program = Effect.gen(function*() {
// ... snip ...
const tokenOrder = yield* TokenOrder.make({ source, destination, sender: "union122ny3mep2l7nhtafpwav2y9e5jrslhek76hsjl", receiver: "0x50A22f95bcB21E7bFb63c7A8544AC0683dCeA302", baseToken: "au", baseAmount: 10n, quoteToken: "0xba5eD44733953d79717F6269357C77718C8Ba5ed", quoteAmount: 10n, kind: "solve", metadata: "0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000014ba5ed44733953d79717f6269357c77718c8ba5ed0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", version: 2, })})
Finally, the token order you’ve constructed can be used as an instruction
to create a ZkgmClientRequest
.
import { TokenOrder, ZkgmClient, ZkgmClientRequest, ZkgmClientResponse } from "@unionlabs/sdk"import { ChannelId } from "@unionlabs/sdk/schema/channel"import { Effect, Logger } from "effect"
const program = Effect.gen(function*() {
// ... snip ...
const request = ZkgmClientRequest.make({ source, destination, channelId: ChannelId.make(1), ucs03Address: "union1336jj8ertl8h7rdvnz4dh5rqahd09cy0x43guhsxx6xyrztx292qpe64fh", instruction: tokenOrder, })})
Now that you’ve created a full zkgm request, you can execute it and wait on the response to close out the program.
import { TokenOrder, ZkgmClient, ZkgmClientRequest, ZkgmClientResponse } from "@unionlabs/sdk"import { Effect, Logger } from "effect"
const program = Effect.gen(function*() {
// ... snip ...
const zkgmClient = yield* ZkgmClient.ZkgmClient
const response: ZkgmClientResponse.ZkgmClientResponse = yield* zkgmClient.execute(request)
yield* Effect.log("TX Hash:", response.txHash)})
With the program ready, we can now use Effect to execute our transfer and listen for a response.
Below, several items of note are provided to the program:
Cosmos.SigningClient
connected to a Union Testnet RPC- This contains a manually crated key pair (normally fetched from wallet)
- Network base gas price
Cosmos.Client
connected to a Union Testnet RPC
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"import { GasPrice } from "@cosmjs/stargate"import { Cosmos, CosmosZkgmClient } from "@unionlabs/sdk-cosmos"import { ChainRegistry } from "@unionlabs/sdk/ChainRegistry"import { Effect, Logger } from "effect"
const program = Effect.gen(function*() { // ... program ...}).pipe( Effect.provide(CosmosZkgmClient.layerWithoutSigningClient), Effect.provide(Cosmos.SigningClient.Live( "union122ny3mep2l7nhtafpwav2y9e5jrslhek76hsjl", "https://rpc.union-testnet-10.union.chain.kitchen", await DirectSecp256k1HdWallet.fromMnemonic( "memo memo memo", { prefix: "union" }, ), { gasPrice: GasPrice.fromString("100000au") }, )), Effect.provide(Cosmos.Client.Live("https://rpc.union-testnet-10.union.chain.kitchen")), Effect.provide(ChainRegistry.Default), Effect.provide(Logger.replace(Logger.defaultLogger, Logger.prettyLoggerDefault)),)
Effect.runPromise(program) .then(console.log) .catch(console.error)
You have now created and executed a transfer from a Cosmos chain using USC03-ZKGM with the Union TS SDK 🎉.
For ease of use, you can refer to the complete example “Send Funds Union -> Sepolia”.
Happy building!