Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
127a60a
chore(ts-sdk-sui): started
Caglankaan Sep 24, 2025
e7ea531
chore(ts-sdk-sui): added new function
Caglankaan Sep 24, 2025
52dcff8
chore(ts-sdk-sui): added new function
Caglankaan Sep 24, 2025
1b72804
chore(ts-sdk-sui): added new function
Caglankaan Sep 24, 2025
d9544ce
chore(ts-sdk-sui): added new functions
Caglankaan Sep 24, 2025
321dd24
chore(ts-sdk-sui): added different examples
Caglankaan Sep 24, 2025
32bdba6
chore(ts-sdk-sui): added comments
Caglankaan Sep 24, 2025
e916e1c
chore(ts-sdk-sui): created submit instruction function
Caglankaan Sep 25, 2025
a1b6f08
chore(ts-sdk-sui): added readCoinMeta function
Caglankaan Sep 26, 2025
99ed826
chore(ts-sdk-sui): fromWallet function is being called, error fixed o…
Caglankaan Sep 26, 2025
7fdf910
chore(ts-sdk-sui): fromWallet improvements
Caglankaan Sep 26, 2025
6825e0b
chore(ts-sdk-sui): working POC added
Caglankaan Sep 26, 2025
d2238ad
chore(ts-sdk-sui): fixed token order , still issues with display
Caglankaan Sep 29, 2025
2ec3db8
chore(ts-sdk-sui): added suidisplay
Caglankaan Sep 29, 2025
cbfe7c2
chore(ts-sdk-sui): added suitoken
Caglankaan Sep 30, 2025
1a5e346
chore(ts-sdk-sui): fully functional ts-sdk example for sui->union
Caglankaan Sep 30, 2025
bbb70a9
chore(ts-sdk-sui): nix-fmt applied
Caglankaan Oct 1, 2025
00459af
chore(ts-sdk-sui): fixed ts-sdk-evm error
Caglankaan Oct 1, 2025
c80d88f
chore(ts-sdk-sui): added sui to generateSalt type
Caglankaan Oct 1, 2025
7caace9
chore(ts-sdk-sui): added transport interface for extra params
Caglankaan Oct 1, 2025
951db4c
chore(ts-sdk-sui): some cleanup
Caglankaan Oct 3, 2025
08f1ee3
chore(ts-sdk-sui): fixing ci errors
Caglankaan Oct 6, 2025
11b4efb
chore(ts-sdk-sui): fixing ci errors
Caglankaan Oct 6, 2025
de77b97
chore(ts-sdk-sui): fixing ci errors
Caglankaan Oct 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ ts-sdk-evm/docs
ts-sdk-cosmos/build
ts-sdk-cosmos/dist
ts-sdk-cosmos/docs
ts-sdk-sui/build
ts-sdk-sui/dist
ts-sdk-sui/docs
sentinel2/build
docs/src/content/docs/reference/@unionlabs/sdk
docs/src/content/docs/reference/@unionlabs/sdk-evm
Expand Down
4 changes: 4 additions & 0 deletions app2/src/lib/stores/wallets.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ class WalletsStore {
evmAddress: Option.Option<Ucs05.EvmDisplay> = $state(Option.none())
cosmosAddress: Option.Option<Ucs05.CosmosDisplay> = $state(Option.none())
aptosAddress: Option.Option<Ucs05.AnyDisplay> = $state(Option.none())
suiAddress: Option.Option<Ucs05.AnyDisplay> = $state(Option.none())
inputAddress: Option.Option<Ucs05.AnyDisplay> = $state(Option.none())

hasAnyWallet() {
return (
Option.isSome(this.evmAddress)
|| Option.isSome(this.cosmosAddress)
|| Option.isSome(this.aptosAddress)
|| Option.isSome(this.suiAddress)
|| Option.isSome(this.inputAddress)
)
}
Expand All @@ -34,6 +36,7 @@ class WalletsStore {
this.evmAddress,
this.cosmosAddress,
this.aptosAddress,
this.suiAddress,
]),
A.map(Ucs05.anyDisplayToCanonical),
)
Expand All @@ -52,6 +55,7 @@ class WalletsStore {
Option.map((address) => Ucs05.CosmosDisplay.make({ address })),
)),
Match.when("aptos", () => this.aptosAddress),
Match.when("sui", () => this.suiAddress),
Match.exhaustive,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ export const checkAllowances = Effect.fn((
sender,
chain,
),
SuiDisplay: (sender) =>
Effect.fail(
new AllowanceCheckError({ message: "Sui allowance check not implemented" }),
),
}),
Effect.map(A.map(({ token, allowance }) => [token, allowance] as const)),
Effect.map(HashMap.fromIterable),
Expand Down
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@
./ts-sdk/ts-sdk.nix
./ts-sdk-evm/ts-sdk-evm.nix
./ts-sdk-cosmos/ts-sdk-cosmos.nix
./ts-sdk-sui/ts-sdk-sui.nix
./typescript-sdk/typescript-sdk.nix
./cosmwasm/cosmwasm.nix
./evm/evm.nix
Expand Down
1 change: 1 addition & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ packages:
- 'ts-sdk-evm'
- 'typescript-sdk'
- 'zkgm-dev'
- 'ts-sdk-sui'
1 change: 1 addition & 0 deletions ts-sdk-sui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/**
21 changes: 21 additions & 0 deletions ts-sdk-sui/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 Union.fi Labs, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
3 changes: 3 additions & 0 deletions ts-sdk-sui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Union TypeScript SDK for SUI

`@unionlabs/sdk-sui`
5 changes: 5 additions & 0 deletions ts-sdk-sui/docgen.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "../node_modules/@effect/docgen/schema.json",
"srcLink": "https://github.com/unionlabs/union/tree/main/ts-sdk-sui/src/",
"exclude": ["src/internal/**/*.ts"]
}
119 changes: 119 additions & 0 deletions ts-sdk-sui/examples/sui-create-client-generate-instruction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// @ts-ignore
if (typeof BigInt.prototype.toJSON !== "function") {
// @ts-ignore
BigInt.prototype.toJSON = function() {
return this.toString()
}
}
import { getFullnodeUrl } from "@mysten/sui/client"
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519"
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"
import {
PublicClient,
readCoinBalances,
readCoinMetadata,
sendInstruction,
WalletClient,
writeContract,
} from "../src/Sui.js"
import { layerWithoutWallet } from "../src/SuiZkgmClient.js"

import { Transaction } from "@mysten/sui/transactions"
import { ChainRegistry } from "@unionlabs/sdk/ChainRegistry"
import { UniversalChainId } from "@unionlabs/sdk/schema/chain"
import * as TokenOrder from "@unionlabs/sdk/TokenOrder"

const MNEMONIC = process.env.SUI_MNEMONIC ?? "..."
const RECIPIENT = process.env.RECIPIENT
?? "union1wycy8g8v5sff6gsjl9yhjs43q98xpl05p3gn2s"

const keypair = Ed25519Keypair.deriveKeypair(MNEMONIC)

const program = Effect.gen(function*() {
// TODO: Source will be SUI testnet
const source = yield* ChainRegistry.byUniversalId(
UniversalChainId.make("ethereum.17000"),
)

console.log("source", source)

const destination = yield* ChainRegistry.byUniversalId(
UniversalChainId.make("union.union-1"),
)
const wallet = yield* WalletClient

const sender = wallet.signer.toSuiAddress()

console.log("sender:", sender)

const tokenOrder = yield* TokenOrder.make({
source,
destination,
sender: sender,
receiver: RECIPIENT,
baseToken: "0x2::sui::SUI",
baseAmount: 10000000n,
quoteToken: "union1y05e0p2jcvhjzf7kcqsrqx93d4g3u93hc2hykaq8hrvkqrp5ltrssagzyd",
quoteAmount: 10000000n,
kind: "solve",
metadata:
"0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040756e696f6e31793035653070326a6376686a7a66376b63717372717839336434673375393368633268796b6171386872766b717270356c7472737361677a7964",
version: 2,
})

const request = ZkgmClientRequest.make({
source,
destination,
channelId: ChannelId.make(5),
ucs03Address: "0x8675045186976da5b60baf20dc94413fb5415a7054052dc14d93c13d3dbdf830",
instruction: tokenOrder,

// NEW — only read by the Sui client
transport: {
sui: {
relayStoreId: "0x393a99c6d55d9a79efa52dea6ea253fef25d2526787127290b985222cc20a924",
vaultId: "0x7c4ade19208295ed6bf3c4b58487aa4b917ba87d31460e9e7a917f7f12207ca3",
ibcStoreId: "0xac7814eebdfbf975235bbb796e07533718a9d83201346769e5f281dc90009175",
coins: [
{
typeArg: "0x2::sui::SUI",
objectId: "0x266d00c4b329111255339c041cc57a1b616cfeddafdae47df8f814002578e95b",
},
],
},
},
})

yield* Effect.log("ZKGM Client Request", request)

const zkgmClient = yield* ZkgmClient.ZkgmClient

const response: ZkgmClientResponse.ZkgmClientResponse = yield* zkgmClient.execute(request)

yield* Effect.log("Submission Hash", response.txHash)
}).pipe(
Effect.provide(layerWithoutWallet),
Effect.provide(PublicClient.Live({ url: getFullnodeUrl("testnet") })),
Effect.provide(
WalletClient.Live({
url: getFullnodeUrl("testnet"),
signer: keypair,
}),
),
Effect.provide(ChainRegistry.Default),
Effect.provide(Logger.replace(Logger.defaultLogger, Logger.prettyLoggerDefault)),
)

Effect.runPromise(program).catch((e: any) => {
console.error("\n--- TOP-LEVEL ERROR ---")
console.dir(e, { depth: 10 })
if (e?.cause) {
console.error("\n--- ORIGINAL CAUSE ---")
console.dir(e.cause, { depth: 10 })
}
})
57 changes: 57 additions & 0 deletions ts-sdk-sui/examples/sui-create-client-read-coin-related.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// @ts-ignore
if (typeof BigInt.prototype.toJSON !== "function") {
// @ts-ignore
BigInt.prototype.toJSON = function() {
return this.toString()
}
}

import { getFullnodeUrl } from "@mysten/sui/client"
import { Effect, Logger } from "effect"

import {
getAllCoinsUnique,
getCoinDecimals,
getCoinName,
PublicClient,
readCoinBalances,
readCoinMetadata,
readCoinSymbol,
readTotalCoinBalance,
} from "../src/Sui.js"

const ADDRESS = process.env.ADDRESS
?? "0x03ff9dd9e093387bdd4432c6a3eb6a1bd5a8f39a530042ac7efe576f18d3232b"

const COIN_TYPE = "0x2::sui::SUI" as any

const program = Effect.gen(function*() {
const { client } = yield* PublicClient
yield* Effect.log("Sui public client initialized", client.network)

const meta = yield* readCoinMetadata(COIN_TYPE)
yield* Effect.log("SUI metadata", meta)

const [name, symbol, decimals] = yield* Effect.all([
getCoinName(COIN_TYPE),
readCoinSymbol(COIN_TYPE),
getCoinDecimals(COIN_TYPE),
])
yield* Effect.log("SUI meta (granular)", { name, symbol, decimals })

yield* Effect.log("Address", ADDRESS)
const coins = yield* readCoinBalances(COIN_TYPE, ADDRESS as any)
yield* Effect.log("SUI coins (objects)", coins)

const total = yield* readTotalCoinBalance(COIN_TYPE, ADDRESS as any)
yield* Effect.log("SUI total balance (mist as BigInt)", total.toString())

const unique = yield* getAllCoinsUnique(ADDRESS as any)

yield* Effect.log("All coins (unique, summed)", unique)
}).pipe(
Effect.provide(PublicClient.Live({ url: getFullnodeUrl("testnet") })),
Effect.provide(Logger.replace(Logger.defaultLogger, Logger.prettyLoggerDefault)),
)

Effect.runPromise(program).catch(console.error)
69 changes: 69 additions & 0 deletions ts-sdk-sui/examples/sui-create-client-write-contract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// @ts-ignore
if (typeof BigInt.prototype.toJSON !== "function") {
// @ts-ignore
BigInt.prototype.toJSON = function() {
return this.toString()
}
}
import { getFullnodeUrl } from "@mysten/sui/client"
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519"
import { Transaction } from "@mysten/sui/transactions"
import { Effect, Logger } from "effect"
import {
PublicClient,
readCoinBalances,
readCoinMetadata,
WalletClient,
writeContract,
} from "../src/Sui.js"

const MNEMONIC = process.env.SUI_MNEMONIC ?? "..."
const RECIPIENT = process.env.RECIPIENT
?? "0x03ff9dd9e093387bdd4432c6a3eb6a1bd5a8f39a530042ac7efe576f18d3232b"

const keypair = Ed25519Keypair.deriveKeypair(MNEMONIC)

const program = Effect.gen(function*() {
const { client } = yield* PublicClient
yield* Effect.log("Sui public client initialized", client.network)
const meta = yield* readCoinMetadata("0x2::sui::SUI" as any)
yield* Effect.log("SUI metadata", meta)

yield* Effect.log("keypair.getPublicKey().toSuiAddress()", keypair.getPublicKey().toSuiAddress())
const balances = yield* readCoinBalances(
"0x2::sui::SUI" as any,
keypair.getPublicKey().toSuiAddress() as any,
)
yield* Effect.log("SUI balances", balances)

const wallet = yield* WalletClient
const amountMist = 10_000_000n // 0.01 SUI

const tx = new Transaction()
const coin = tx.splitCoins(tx.gas, [tx.pure.u64(amountMist)])
const recipient = tx.pure.address(RECIPIENT)

const res = yield* writeContract(
client,
keypair,
"0x2", // packageId: Sui framework
"transfer", // module: sui::transfer
"public_transfer", // function
["0x2::coin::Coin<0x2::sui::SUI>"], // type arg T
[coin, recipient], // (obj: T, recipient: address)
tx,
)

yield* Effect.log("Transfer submitted", res)
}).pipe(
Effect.provide(PublicClient.Live({ url: getFullnodeUrl("testnet") })),
Effect.provide(
WalletClient.Live({
url: getFullnodeUrl("testnet"),
signer: keypair, // ✅ Sui signer
}),
),
Effect.provide(Logger.replace(Logger.defaultLogger, Logger.prettyLoggerDefault)),
)

Effect.runPromise(program).catch(console.error)
Loading
Loading