Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
9e1f68e
feat(app,ts-sdk): add staking ui
ehegnes Sep 2, 2025
7382f98
fix: split mint amount and spend amount
benluelo Sep 4, 2025
adf6cc9
feat(app2): unstake progress
ehegnes Sep 4, 2025
3bd02ce
fix: unbond example begin bond app integration
ehegnes Sep 4, 2025
8b5d1c3
chore(ts-sdk): add ben wisdom
ehegnes Sep 5, 2025
f577da4
fix: wip
ehegnes Sep 7, 2025
a6248d9
fix: ben wip
ehegnes Sep 8, 2025
a02e770
feat: holy bond
ehegnes Sep 9, 2025
ebcc0f0
feat: bond flatten
ehegnes Sep 9, 2025
7611dc6
feat: unbond working
ehegnes Sep 10, 2025
57e35e9
chore: for sharing w/ lukas
ehegnes Sep 10, 2025
9036058
fix(ts-sdk-evm,ts-sdk-cosmos): avoid leaking utility requirements as …
ehegnes Sep 10, 2025
efd4df4
feat(app): breakout to component
Swepool Sep 11, 2025
307b8a9
feat(app): breakout to component
Swepool Sep 11, 2025
dba4a14
feat(app): update page
Swepool Sep 11, 2025
641bcbc
chore(app): clean up
Swepool Sep 11, 2025
e3a9301
feat(app): fix state
Swepool Sep 11, 2025
dccec1e
chore(app): fmt
Swepool Sep 11, 2025
157833a
fix(app): push for sanity check
Swepool Sep 11, 2025
2a7cd49
chore(app): types check out
ehegnes Sep 11, 2025
66bd901
fix(ts-sdk-evm): halt indexer lifecycle event emission until later time
ehegnes Sep 11, 2025
9ea6f7a
feat(app): fix wait for indexer
Swepool Sep 11, 2025
f849b44
feat(app): save a bit of styling
Swepool Sep 12, 2025
1231c10
feat(app): unbond bond basic pages
Swepool Sep 12, 2025
2348a50
feat(app): clean up new pages
Swepool Sep 12, 2025
9920d76
chore(app): fmt
Swepool Sep 12, 2025
57abd82
feat(app): and two page ts
Swepool Sep 12, 2025
340f97a
fix(app): change nav
Swepool Sep 12, 2025
cb7e4c1
fix(app): change to sepolia
Swepool Sep 12, 2025
1bc0c97
fix(app): point to mainnet
Swepool Sep 13, 2025
d1f2c68
feat(app): incentive wip
Swepool Sep 13, 2025
0497b3b
fix(app): proxy
Swepool Sep 13, 2025
c9f6496
fix(app): change to sepolia and union testnet
Swepool Sep 13, 2025
54ead79
fix(app): remove staker
Swepool Sep 13, 2025
97a59fa
fix(app): channels
Swepool Sep 13, 2025
92cb1c8
fix(app): log incentive
Swepool Sep 13, 2025
9d379d0
fix(app): change approval
Swepool Sep 13, 2025
47a1dcc
fix(app): normalize input
Swepool Sep 13, 2025
4fe7a82
chore(app): fmt
Swepool Sep 13, 2025
2f19175
fix(app): clean up approval and add state
Swepool Sep 13, 2025
6db9f79
fix(app): approval safe
Swepool Sep 13, 2025
1f5b68c
fix(app): resolved hash
Swepool Sep 13, 2025
93c03d3
fix(app): revert
Swepool Sep 13, 2025
857ca56
fix(app): move state
Swepool Sep 13, 2025
7706411
feat(ts-sdk-evm): changes to safe lifecycle
Swepool Sep 13, 2025
fb3e357
feat(app): use new lifecycle approach
Swepool Sep 13, 2025
3b50e49
feat(ts-sdk-evm): extend safe support wip
Swepool Sep 13, 2025
8c86520
feat(app): use new safe approach
Swepool Sep 13, 2025
8c199ca
feat(app): cleaner provide
Swepool Sep 13, 2025
5e53f72
fix(app): add logs
Swepool Sep 13, 2025
e61aa2b
fix(app): add more logs
Swepool Sep 13, 2025
f50dc4f
fix(app): provide safe first
Swepool Sep 13, 2025
ec064f9
fix(app): wip test approach
Swepool Sep 13, 2025
168329e
fix(app): clean and wait for receipt
Swepool Sep 13, 2025
8a7880f
fix(ts-sdk-evm): revert
Swepool Sep 13, 2025
67c4b05
chore(app): fmt and clean up
Swepool Sep 13, 2025
5b21cb2
fix(app): point to mainnet
Swepool Sep 15, 2025
9afd4b0
fix(app): change minter
Swepool Sep 15, 2025
03f1b6d
feat(app): save design and clean up wip
Swepool Sep 18, 2025
48cba92
feat(app): open wallet and cleaner match
Swepool Sep 19, 2025
18b4b7f
fix(app): adjust tabs size
Swepool Sep 19, 2025
0865d04
fix(app): typo
ehegnes Sep 18, 2025
e18ba7c
chore(app,ts-sdk,ts-sdk-evm): nix fmt
ehegnes Sep 18, 2025
d4771ee
refactor(app): prefer BigDecimal over floats
ehegnes Sep 18, 2025
2b86b1f
fix(app): unbond progress
Swepool Sep 22, 2025
67826f9
fix(app): update bond example
Swepool Sep 23, 2025
d62373c
feat(app): reusable instantiate and testnet
Swepool Sep 23, 2025
2587b2b
feat(app): withdrawal
Swepool Sep 23, 2025
e7fe720
chore(app): remove old file
Swepool Sep 23, 2025
a3e7d3f
chore(app): update schema
Swepool Sep 23, 2025
2f59a08
feat(app): clean up wip
Swepool Sep 23, 2025
58b13e3
feat(app): clean up wip
Swepool Sep 24, 2025
73daf20
fix: fix build
Swepool Sep 24, 2025
48332f1
fix(ts-sdk): add since
Swepool Sep 24, 2025
9f87f98
fix(app): handle interuption
Swepool Sep 24, 2025
610f1a8
feat(ts-sdk): add util
Swepool Sep 25, 2025
ea2995c
fix(app): refresh table
Swepool Sep 25, 2025
9bde49a
feat(app): use util and point to mainnet
Swepool Sep 25, 2025
8d76e31
fix(app): get params while client side nav
Swepool Sep 25, 2025
e2138dc
feat(app): escher text logo
Swepool Sep 25, 2025
6cb1acc
feat(app): get rate once and pass as prop
Swepool Sep 25, 2025
0b3b6c7
fix(app): should be mainnet
Swepool Sep 25, 2025
862ea50
feat(app): button state
Swepool Sep 25, 2025
21d69ad
chore(app): fmt
Swepool Sep 25, 2025
0561ce8
feat(app): change slippage
Swepool Sep 25, 2025
f6c2cd3
fix(app): point url to mainnet
Swepool Sep 25, 2025
bc11079
fix(app): build
Swepool Sep 25, 2025
5c6258d
chore(ts-sdk): skip old test
ehegnes Sep 25, 2025
2824c09
feat(app): pull supabase types
Swepool Sep 25, 2025
f4d29fe
feat(app): point to eu claim
Swepool Sep 25, 2025
402ce4e
fix(app): change logo
Swepool Sep 25, 2025
0f8653b
fix(app): update contract address etc
Swepool Sep 25, 2025
8b15b1d
fix(app): fix build
Swepool Sep 25, 2025
c2191d6
fix(app): update text for eU
Swepool Sep 25, 2025
475d6e0
chore(app): fmt
Swepool Sep 25, 2025
0b803a1
fix(app): use btn instead
Swepool Sep 25, 2025
24fc442
fix(app): reduce quote token error length
ehegnes Sep 25, 2025
00d8ec2
fix(app): rename to eu and point to prod graphql
Swepool Sep 25, 2025
385a7c6
fix(app): point to landing
Swepool Sep 25, 2025
65d7223
fix(app): make multisig work with multiple source chains
ehegnes Sep 25, 2025
247b916
fix(app): two small bugs
Swepool Sep 25, 2025
3c6b59f
fix(app): change auth guard
Swepool Sep 26, 2025
05c9c14
fix(app): clean up page
Swepool Sep 26, 2025
0f0da9f
fix(app): flex 1 and default slippage
Swepool Sep 26, 2025
7757944
feat(app): escher banner
Swepool Sep 26, 2025
aa3eaa7
fix(app): update styling
Swepool Sep 26, 2025
76ff261
feat(app): add dust state
Swepool Sep 26, 2025
3ad75f6
fix(app): no mono
Swepool Sep 26, 2025
44a10fb
feat(app): add rewards and dust
Swepool Sep 26, 2025
ffcd27e
fix(app): multisig input validation and safe UI
ehegnes Sep 26, 2025
f85f50d
chore: nix fmt
ehegnes Sep 26, 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
300 changes: 222 additions & 78 deletions app2/examples/bond.ts

Large diffs are not rendered by default.

217 changes: 185 additions & 32 deletions app2/examples/unbond.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ if (typeof BigInt.prototype.toJSON !== "function") {
import {
Batch,
Call,
Token,
TokenOrder,
Ucs05,
ZkgmClient,
Expand All @@ -22,16 +23,16 @@ import {
import { Evm, EvmZkgmClient } from "@unionlabs/sdk-evm"
import { ChainRegistry } from "@unionlabs/sdk/ChainRegistry"
import {
ON_ZKGM_CALL_PROXY,
U_BANK,
U_ERC20,
U_TO_UNION_SOLVER_METADATA,
EU_ERC20,
EU_LST,
EU_SOLVER_ON_UNION_METADATA,
EU_STAKING_HUB,
} from "@unionlabs/sdk/Constants"
import { UniversalChainId } from "@unionlabs/sdk/schema/chain"
import { ChannelId } from "@unionlabs/sdk/schema/channel"
import { HexFromJson } from "@unionlabs/sdk/schema/hex"
import { Effect, Logger, pipe, Schema } from "effect"
import { http } from "viem"
import { bytesToHex, encodeAbiParameters, fromHex, http, keccak256 } from "viem"
import { privateKeyToAccount } from "viem/accounts"
import { holesky } from "viem/chains"

Expand All @@ -40,76 +41,223 @@ const JsonFromBase64 = Schema.compose(
Schema.parseJson(),
)

const AMOUNT = 1n
const AMOUNT = 5n
const ETHEREUM_CHAIN_ID = UniversalChainId.make("ethereum.17000")
const UNION_CHAIN_ID = UniversalChainId.make("union.union-testnet-10")
const SOURCE_CHANNEL_ID = ChannelId.make(1) // FIXME
const UCS03_MINTER = Ucs05.EvmDisplay.make({
const UCS03_ZKGM = Ucs05.CosmosDisplay.make({
address: "union1336jj8ertl8h7rdvnz4dh5rqahd09cy0x43guhsxx6xyrztx292qpe64fh",
})
const SOURCE_CHANNEL_ID = ChannelId.make(6)
const DESTINATION_CHANNEL_ID = ChannelId.make(20)
const UCS03_EVM = Ucs05.EvmDisplay.make({
address: "0x5fbe74a283f7954f10aa04c2edf55578811aeb03",
})
const VIEM_CHAIN = holesky
const RPC_URL = "https://rpc.17000.ethereum.chain.kitchen"
const VIEM_ACCOUNT = privateKeyToAccount(
process.env.KEY as any,
)
const SENDER = Ucs05.EvmDisplay.make({
address: "0x06627714f3F17a701f7074a12C02847a5D2Ca487",
})
const EU_STAKING_HUB = Ucs05.CosmosDisplay.make({
address: "union1eueueueu9var4yhdruyzkjcsh74xzeug6ckyy60hs0vcqnzql2hq0lxc2f", // FIXME
address: VIEM_ACCOUNT.address,
})

const VIEM_ACCOUNT = privateKeyToAccount(
process.env.KEY as any,
const checkAndSubmitAllowance = pipe(
Evm.readErc20Allowance(
EU_ERC20.address,
SENDER.address,
UCS03_EVM.address,
),
Effect.flatMap((amount) =>
Effect.if(amount < AMOUNT, {
onTrue: () =>
pipe(
Effect.log(`Increasing allowance by ${AMOUNT - amount} for ${EU_ERC20.address}`),
Effect.andThen(() =>
pipe(
Evm.increaseErc20Allowance(
EU_ERC20.address,
UCS03_EVM,
AMOUNT - amount,
),
Effect.andThen(Evm.waitForTransactionReceipt),
)
),
),
onFalse: () =>
Effect.log(`Allowance fulfilled by ${AMOUNT - amount} for ${EU_ERC20.address}`),
})
),
)

const bytecode_base_checksum =
"0xec827349ed4c1fec5a9c3462ff7c979d4c40e7aa43b16ed34469d04ff835f2a1" as const
const canonical_zkgm = Ucs05.anyDisplayToCanonical(UCS03_ZKGM)
const module_hash = "0x120970d812836f19888625587a4606a5ad23cef31c8684e601771552548fc6b9" as const

const instantiate2 = Effect.fn(
function*(options: { path: bigint; channel: ChannelId; sender: Ucs05.AnyDisplay }) {
const sender = yield* Ucs05.anyDisplayToZkgm(options.sender)
const abi = [
{
name: "path",
type: "uint256",
internalType: "uint256",
},
{
name: "channelId",
type: "uint32",
internalType: "uint32",
},
{
name: "sender",
type: "bytes",
internalType: "bytes",
},
] as const

const args = [
options.path,
options.channel,
sender,
] as const

const encode = Effect.try(() =>
encodeAbiParameters(
abi,
args,
)
)

const encoded = yield* encode

/**
* n as BE rep
*/
const u64toBeBytes = (n: bigint) => {
const buffer = new ArrayBuffer(8)
const view = new DataView(buffer)
view.setBigUint64(0, n)
return new Uint8Array(view.buffer)
}

const sha256 = (data: any) => globalThis.crypto.subtle.digest("SHA-256", data)

const salt = keccak256(encoded, "bytes")

const _args = [
...fromHex(module_hash, "bytes"),
...new TextEncoder().encode("wasm"),
0, // null byte
...u64toBeBytes(32n), // checksum len as 64-bit big endian bytes of int
...fromHex(bytecode_base_checksum, "bytes"),
...u64toBeBytes(32n), // creator canonical addr len
...fromHex(canonical_zkgm, "bytes"),
...u64toBeBytes(32n), // len
...salt,
...u64toBeBytes(0n),
] as const

const data = Uint8Array.from(_args)

const r = yield* Effect.tryPromise(() => sha256(data))

const rBytes = bytesToHex(new Uint8Array(r))

const transform = Ucs05.Bech32FromCanonicalBytesWithPrefix("union")

const r2 = yield* Schema.decode(transform)(rBytes)

return Ucs05.CosmosDisplay.make({ address: r2 })
},
)

const sendUnbond = Effect.gen(function*() {
const ethereumChain = yield* ChainRegistry.byUniversalId(ETHEREUM_CHAIN_ID)
const unionChain = yield* ChainRegistry.byUniversalId(UNION_CHAIN_ID)

const eu_staking_hub = yield* Ucs05.anyDisplayToZkgm(EU_STAKING_HUB)
const receiver = yield* instantiate2({
path: 0n,
channel: DESTINATION_CHANNEL_ID,
sender: SENDER,
})

const tokenOrder = yield* TokenOrder.make({
source: ethereumChain,
destination: unionChain,
sender: SENDER,
receiver: ON_ZKGM_CALL_PROXY,
baseToken: U_ERC20,
receiver,
baseToken: EU_ERC20,
baseAmount: AMOUNT,
quoteToken: U_BANK,
quoteToken: Token.Cw20.make({ address: EU_LST.address }),
quoteAmount: AMOUNT,
kind: "solve",
metadata: U_TO_UNION_SOLVER_METADATA,
metadata: EU_SOLVER_ON_UNION_METADATA,
version: 2,
})

const increaseAllowanceCall = yield* pipe(
{
increase_allowance: {
spender: EU_STAKING_HUB.address,
amount: AMOUNT,
},
} as const,
Schema.encode(JsonFromBase64),
Effect.map((msg) => ({
wasm: {
execute: {
contract_addr: EU_LST.address,
msg,
funds: [],
},
},
} as const)),
)

const unbondCall = yield* pipe(
{ amount: tokenOrder.quoteAmount } as const,
{
unbond: {
staker: receiver.address,
amount: tokenOrder.quoteAmount,
},
} as const,
Schema.encode(JsonFromBase64),
Effect.map((msg) => ({
contract: eu_staking_hub,
msg,
funds: [],
call_action: "call_proxy",
wasm: {
execute: {
contract_addr: EU_STAKING_HUB.address,
msg,
funds: [],
},
},
} as const)),
Effect.flatMap(Schema.decode(HexFromJson)),
)

const calls = yield* pipe(
[
increaseAllowanceCall,
unbondCall,
],
Schema.decode(HexFromJson),
Effect.map((contractCalldata) =>
Call.make({
sender: SENDER,
eureka: false,
contractAddress: ON_ZKGM_CALL_PROXY,
contractAddress: receiver,
contractCalldata,
})
),
)

const batch = Batch.make([
tokenOrder,
unbondCall,
calls,
])

const request = ZkgmClientRequest.make({
source: ethereumChain,
destination: unionChain,
channelId: SOURCE_CHANNEL_ID,
ucs03Address: UCS03_MINTER.address,
ucs03Address: UCS03_EVM.address,
instruction: batch,
})

Expand All @@ -123,7 +271,13 @@ const sendUnbond = Effect.gen(function*() {
)

yield* Effect.log("Receipt:", receipt)
}).pipe(
})

pipe(
Effect.all([
checkAndSubmitAllowance,
sendUnbond,
]),
Effect.provide(EvmZkgmClient.layerWithoutWallet),
Effect.provide(Evm.WalletClient.Live({
account: VIEM_ACCOUNT,
Expand All @@ -143,8 +297,7 @@ const sendUnbond = Effect.gen(function*() {
mode: "tty",
}),
)),
Effect.runPromise,
)

Effect.runPromise(sendUnbond)
.then(console.log)
.catch(console.error)
Loading
Loading