diff --git a/docs/astro.config.ts b/docs/astro.config.ts index d928d1b896..3470f108ad 100644 --- a/docs/astro.config.ts +++ b/docs/astro.config.ts @@ -24,6 +24,7 @@ const { PORT = 4321, ENABLE_DEV_TOOLBAR = "false" } = loadEnv( "", ) +// @ts-ignore export default defineConfig({ site: SITE_URL, output: "static", @@ -297,16 +298,38 @@ export default defineConfig({ link: "/integrations/typescript", }, { - label: "Examples (EVM)", - autogenerate: { - directory: "/integrations/typescript/examples/evm", - }, + label: "Guides (EVM)", + items: [ + { + label: "Guide: Send Funds Holesky → Sepolia", + link: "/integrations/typescript/guided-tutorial/evm-holesky-sepolia", + }, + { + label: "Example: Send Funds Holesky → Sepolia", + link: "/integrations/typescript/examples/evm/send-funds-holesky-to-sepolia/", + }, + ], }, { - label: "Examples (Cosmos)", - autogenerate: { - directory: "/integrations/typescript/examples/cosmos", - }, + label: "Guides (Cosmos)", + items: [ + { + label: "Guide: Cross Chain Contract Call", + link: "/integrations/typescript/guided-tutorial/cosmos-call", + }, + { + label: "Example: Cross Chain Contract Call", + link: "/integrations/typescript/examples/cosmos/call/", + }, + { + label: "Guide: Send Funds Union → Sepolia", + link: "/integrations/typescript/guided-tutorial/cosmos-union-sepolia", + }, + { + label: "Example: Send Funds Union → Sepolia", + link: "/integrations/typescript/examples/cosmos/send-funds-union-to-sepolia/", + }, + ], }, ], }, diff --git a/docs/src/content/docs/integrations/typescript/guided-tutorial/cosmos-call.mdx b/docs/src/content/docs/integrations/typescript/guided-tutorial/cosmos-call.mdx new file mode 100644 index 0000000000..e172065899 --- /dev/null +++ b/docs/src/content/docs/integrations/typescript/guided-tutorial/cosmos-call.mdx @@ -0,0 +1,153 @@ +--- +title: Cross Chain Contract Calls +description: Example call on Babylon to Ethereum contract. +--- + +This guide walk's you through writing our example ["Call"](/integrations/typescript/examples/cosmos/call/). The goal of this guide is to show you how to conduct a cross chain contract call using [USC03 - ZKGM](/ucs/03/). In this case we will be calling a contract on Ethereum from Babylon. + +Relevant imports will be included with each step. Outside of libraries provided by Union, this guide uses [Effect](https://effect.website/). + +## Program + +This first section is a walk through of creating the program section of the send funds example. + +### 1. Program Declaration + +Begin by using Effect to create a program function. + +The signer used for this transaction is also declared here. + +```ts +import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing" +import { Effect, Logger } from "effect" + +const signer = await DirectSecp256k1HdWallet.fromMnemonic( + process.env.MEMO ?? "memo memo memo", + { prefix: "bbn" }, +) + +const program = Effect.gen(function*() {}) +``` + +### 2. Source and Destination + +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 Babylon (`babylon.bbn-1`) and the destination is Ethereum (`ethereum.1`). + +```ts +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("babylon.bbn-1"), + ) + + const destination = yield* ChainRegistry.byUniversalId( + UniversalChainId.make("ethereum.1"), + ) +}) +``` + +:::note +The ID's provided here are Universal Chain ID's as defined by [UCS04](/ucs/04). +::: + +### 3. Call + +To create a `Call`, we supply the `sender`, `contractAddress`, and `contractCalldata`. + +More information about `Call` and its fields can be found in the [UCS03 - 0x01 Call Docs](/ucs/03/#0x01---call). + +```ts +import { Call, Ucs05, ZkgmClientRequest, ZkgmClientResponse } from "@unionlabs/sdk" +import { Effect, Logger } from "effect" + +const program = Effect.gen(function*() { + + // ... snip ... + + const call = Call.make({ + sender: Ucs05.CosmosDisplay.make({ + address: "bbn122ny3mep2l7nhtafpwav2y9e5jrslhekrn8frh", + }), + eureka: false, + contractAddress: Ucs05.EvmDisplay.make({ + address: "0x921e5b5091f431f84f14423ec487783a853bc4b0", + }), + contractCalldata: "0xDEADBEEF", + }) +}) +``` + +### 4. zkgm Request + +Finally, with the `Call` ready - you can construct a `ZkgmClientRequest`. + +```ts +import { Call, Ucs05, ZkgmClientRequest, ZkgmClientResponse } from "@unionlabs/sdk" +import { Effect, Logger } from "effect" + +const program = Effect.gen(function*() { + + // ... snip ... + + const request = ZkgmClientRequest.make({ + source, + destination, + channelId: ChannelId.make(3), + ucs03Address: "bbn1336jj8ertl8h7rdvnz4dh5rqahd09cy0x43guhsxx6xyrztx292q77945h", + instruction: call, + }) +}) +``` + +:::note +UCS03 addresses can be found on the [Deployments page](/protocol/deployments/) +::: + +### 5. zkgm Execution and Response + +Now that you’ve created a full zkgm request, you can execute it and wait on the response to close out the program. + +```ts +import { Call, Ucs05, ZkgmClientRequest, ZkgmClientResponse } from "@unionlabs/sdk" +import { GasPrice } from "@cosmjs/stargate" +import { Cosmos, CosmosZkgmClient } from "@unionlabs/sdk-cosmos" +import { Effect, Logger } from "effect" +const program = Effect.gen(function*() { + + // ... snip ... + + const client = yield* CosmosZkgmClient.make.pipe( + Effect.provide(Cosmos.SigningClient.Live( + "bbn122ny3mep2l7nhtafpwav2y9e5jrslhekrn8frh", + "https://rpc.bbn-1.babylon.chain.kitchen", + signer, + { gasPrice: GasPrice.fromString("0.0007ubbn") }, + )), + Effect.provide(Cosmos.Client.Live("https://rpc.bbn-1.babylon.chain.kitchen")), + ) + + const response: ZkgmClientResponse.ZkgmClientResponse = yield* client.execute(request) + + yield* Effect.log("TX Hash:", response.txHash) +}) +``` + +## Execution + +With the program ready, we can now use Effect to execute our transfer and listen for a response. + +```ts +const program = Effect.gen(function*() { + // ... program ... +}).pipe( + Effect.provide(ChainRegistry.Default), + Effect.provide(Logger.replace(Logger.defaultLogger, Logger.prettyLoggerDefault)), +) + +Effect.runPromise(program) + .then(console.log) + .catch(console.error) +``` diff --git a/docs/src/content/docs/integrations/typescript/guided-tutorial/cosmos-union-sepolia.mdx b/docs/src/content/docs/integrations/typescript/guided-tutorial/cosmos-union-sepolia.mdx new file mode 100644 index 0000000000..f00126d9a2 --- /dev/null +++ b/docs/src/content/docs/integrations/typescript/guided-tutorial/cosmos-union-sepolia.mdx @@ -0,0 +1,178 @@ +--- +title: Send Funds Union → Sepolia +description: Example transfer from Union to Sepolia. +--- + +This guide walk's you through writing our example ["Send Funds Union -> Sepolia"](/integrations/typescript/examples/cosmos/send-funds-union-to-sepolia/). The goal of this guide it to show you how to create a token order and submit it to the [UCS03 - ZKGM](/ucs/04) interface. + +Relevant imports will be included with each step. Outside of libraries provided by Union, this guide uses [Effect](https://effect.website/). + +## Program + +This first section is a walk through of creating the program section of the send funds example. + +### 1. Program Declaration + +Begin by using Effect to create a program function. + +```ts +import { Effect, Logger } from "effect" + +const program = Effect.gen(function*() {}) +``` + +### 2. Source and Destination + +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`). + +```ts +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"), + ) +}) +``` + +:::note +The ID's provided here are Universal Chain ID's as defined by [UCS04](/ucs/04). +::: + +### 3. Token Order + +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](/ucs/03/#evm-token-order-examples). + +```ts +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, + }) +}) +``` + +:::note +Solver metadata is supplied here in accordance with [UCS03](/ucs/03) +::: + +### 4. zkgm Request + +Finally, the token order you've constructed can be used as an `instruction` to create a `ZkgmClientRequest`. + +```ts +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, + }) +}) +``` + +:::note +UCS03 addresses can be found on the [Deployments page](/protocol/deployments/) +::: + +### 5. zkgm Execution & Response + +Now that you've created a full zkgm request, you can execute it and wait on the response to close out the program. + +```ts +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) +}) +``` + +## Execution + +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 + +```ts +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"](/integrations/typescript/examples/cosmos/send-funds-union-to-sepolia/). + +Happy building! diff --git a/docs/src/content/docs/integrations/typescript/guided-tutorial/evm-holesky-sepolia.mdx b/docs/src/content/docs/integrations/typescript/guided-tutorial/evm-holesky-sepolia.mdx new file mode 100644 index 0000000000..d179e5347b --- /dev/null +++ b/docs/src/content/docs/integrations/typescript/guided-tutorial/evm-holesky-sepolia.mdx @@ -0,0 +1,198 @@ +--- +title: "Send Funds Holesky → Sepolia" +description: Guide for transfers from Holesky to Sepolia. +--- + +This guide walk's you through writing our example ["Send Funds Holesky -> Sepolia"](/integrations/typescript/examples/evm/send-funds-holesky-to-sepolia/). The goal of this guide it to show you how to create a token order and submit it to the [UCS03 - ZKGM](/ucs/04) interface. + +Relevant imports will be included with each step. Outside of libraries provided by Union, this guide uses [viem](https://viem.sh/) and [Effect](https://effect.website/). + +## Program + +This first section is a walk through of creating the program section of the send funds example. + +### 1. Program Declaration + +Begin by using Effect to create a program function. + +```ts +import { Effect, Logger } from "effect" + +const program = Effect.gen(function*() {}) +``` + +### 2. Source and Destination + +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 Holesky (`ethereum.17000`) and the destination is Sepolia (`ethereum.11155111`). + +```ts +import { ChainRegistry } from "@unionlabs/sdk/ChainRegistry" +import { Effect, Logger } from "effect" + +const program = Effect.gen(function*() { + const source = yield* ChainRegistry.byUniversalId( + UniversalChainId.make("ethereum.17000"), + ) + const destination = yield* ChainRegistry.byUniversalId( + UniversalChainId.make("ethereum.11155111"), + ) +}) +``` + +:::note +The ID's provided here are Universal Chain ID's as defined by [UCS04](/ucs/04). +::: + +### 3. Token Order + +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 contract addresses for LINK. + +We also need to determine the `Kind` for the `TokenOrder`. In this case, we use `esccrow`. 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](/ucs/03/#evm-token-order-examples). + +```ts +import * as TokenOrder from "@unionlabs/sdk/TokenOrder" +import { Effect, Logger } from "effect" + +const program = Effect.gen(function*() { + + // ... snip ... + + const tokenOrder = yield* TokenOrder.make({ + source, + destination, + sender: "0x06627714f3F17a701f7074a12C02847a5D2Ca487", + receiver: "0x50A22f95bcB21E7bFb63c7A8544AC0683dCeA302", + // LINK on Holesky + baseToken: "0x685ce6742351ae9b618f383883d6d1e0c5a31b4b", + baseAmount: 10n, + // Holesky LINK on Sepolia + quoteToken: "0x80fdbf104ec58a527ec40f7b03f88c404ef4ba63", + quoteAmount: 10n, + kind: "escrow", + metadata: undefined, + version: 2, + }) + + yield* Effect.log("Token Order V2", tokenOrder) +}) +``` + +### 4. zkgm Request + +Finally, the token order you've constructed can be used as an `instruction` to create a `ZkgmClientRequest`. + +```ts +import * as ZkgmClientRequest from "@unionlabs/sdk/ZkgmClientRequest" +import { Effect, Logger } from "effect" + +const program = Effect.gen(function*() { + + // ... snip ... + + const request = ZkgmClientRequest.make({ + source, + destination, + channelId: ChannelId.make(2), + ucs03Address: "0x5fbe74a283f7954f10aa04c2edf55578811aeb03", + instruction: tokenOrder, + }) +}) +``` + +:::note +UCS03 addresses can be found on the [Deployments page](/protocol/deployments/) +::: + +### 5. zkgm Execution & Response + +Now that you've created a full zkgm request, you can execute it and wait on the response to close out the program. + +```ts +import { ChannelId } from "@unionlabs/sdk/schema/channel" +import * as ZkgmClient from "@unionlabs/sdk/ZkgmClient" +import * as ZkgmClientRequest from "@unionlabs/sdk/ZkgmClientRequest" +import * as ZkgmClientResponse from "@unionlabs/sdk/ZkgmClientResponse" +import * as ZkgmIncomingMessage from "@unionlabs/sdk/ZkgmIncomingMessage" +import { Effect, Logger } from "effect" + +const program = Effect.gen(function*() { + + // ... snip ... + + const zkgmClient = yield* ZkgmClient.ZkgmClient + + // NOTE: 1. switch chain is assumed + // NOTE: 2. write in progress + + const response: ZkgmClientResponse.ZkgmClientResponse = yield* zkgmClient.execute(request) + + // NOTE: 3. write complete (with tx hash) + + yield* Effect.log("Submission Hash", response.txHash) + + const completion = yield* response.waitFor( + ZkgmIncomingMessage.LifecycleEvent.$is("EvmTransactionReceiptComplete"), + ) + + // NOTE: 4. tx complete + + yield* Effect.log("Completion", completion) +}) +``` + +:::note +***NOTE #1*** - +In this example, it does not matter, as we manually provide the key and specify the transport in [Execution](#execution). If you were developing a web app with a wallet client - you would need to switch the chains here. +::: + +## Execution + +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: + +- `Evm.WalletClient` connected to a Holesky RPC + - Contains a manually created key pair +- `Evm.PublicClient` connected to a Holesky RPC + +```ts +import { Evm, EvmZkgmClient } from "@unionlabs/sdk-evm" +import { ChainRegistry } from "@unionlabs/sdk/ChainRegistry" +import { Effect, Logger } from "effect" +import { http } from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { holesky } from "viem/chains" + +const program = Effect.gen(function*() { + // ... program ... +}).pipe( + Effect.provide(EvmZkgmClient.layerWithoutWallet), + Effect.provide(Evm.WalletClient.Live({ + account: privateKeyToAccount( + (process.env.KEY as any) ?? "0x...", + ), + chain: holesky, + transport: http("https://rpc.17000.ethereum.chain.kitchen"), + })), + Effect.provide(Evm.PublicClient.Live({ + chain: holesky, + transport: http("https://rpc.17000.ethereum.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 an EVM chain using USC03-ZKGM with the Union TS SDK 🎉. + +For ease of use, you can refer to the complete example ["Send Funds Holesky -> Sepolia"](/integrations/typescript/examples/evm/send-funds-holesky-to-sepolia/). + +Happy building!