Skip to content

Commit be5dfb1

Browse files
authored
Sdk stake (#5150)
2 parents b37008e + f85f50d commit be5dfb1

File tree

88 files changed

+8508
-4760
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+8508
-4760
lines changed

app2/examples/bond.ts

Lines changed: 222 additions & 78 deletions
Large diffs are not rendered by default.

app2/examples/unbond.ts

Lines changed: 185 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ if (typeof BigInt.prototype.toJSON !== "function") {
1313
import {
1414
Batch,
1515
Call,
16+
Token,
1617
TokenOrder,
1718
Ucs05,
1819
ZkgmClient,
@@ -22,16 +23,16 @@ import {
2223
import { Evm, EvmZkgmClient } from "@unionlabs/sdk-evm"
2324
import { ChainRegistry } from "@unionlabs/sdk/ChainRegistry"
2425
import {
25-
ON_ZKGM_CALL_PROXY,
26-
U_BANK,
27-
U_ERC20,
28-
U_TO_UNION_SOLVER_METADATA,
26+
EU_ERC20,
27+
EU_LST,
28+
EU_SOLVER_ON_UNION_METADATA,
29+
EU_STAKING_HUB,
2930
} from "@unionlabs/sdk/Constants"
3031
import { UniversalChainId } from "@unionlabs/sdk/schema/chain"
3132
import { ChannelId } from "@unionlabs/sdk/schema/channel"
3233
import { HexFromJson } from "@unionlabs/sdk/schema/hex"
3334
import { Effect, Logger, pipe, Schema } from "effect"
34-
import { http } from "viem"
35+
import { bytesToHex, encodeAbiParameters, fromHex, http, keccak256 } from "viem"
3536
import { privateKeyToAccount } from "viem/accounts"
3637
import { holesky } from "viem/chains"
3738

@@ -40,76 +41,223 @@ const JsonFromBase64 = Schema.compose(
4041
Schema.parseJson(),
4142
)
4243

43-
const AMOUNT = 1n
44+
const AMOUNT = 5n
4445
const ETHEREUM_CHAIN_ID = UniversalChainId.make("ethereum.17000")
4546
const UNION_CHAIN_ID = UniversalChainId.make("union.union-testnet-10")
46-
const SOURCE_CHANNEL_ID = ChannelId.make(1) // FIXME
47-
const UCS03_MINTER = Ucs05.EvmDisplay.make({
47+
const UCS03_ZKGM = Ucs05.CosmosDisplay.make({
48+
address: "union1336jj8ertl8h7rdvnz4dh5rqahd09cy0x43guhsxx6xyrztx292qpe64fh",
49+
})
50+
const SOURCE_CHANNEL_ID = ChannelId.make(6)
51+
const DESTINATION_CHANNEL_ID = ChannelId.make(20)
52+
const UCS03_EVM = Ucs05.EvmDisplay.make({
4853
address: "0x5fbe74a283f7954f10aa04c2edf55578811aeb03",
4954
})
5055
const VIEM_CHAIN = holesky
5156
const RPC_URL = "https://rpc.17000.ethereum.chain.kitchen"
57+
const VIEM_ACCOUNT = privateKeyToAccount(
58+
process.env.KEY as any,
59+
)
5260
const SENDER = Ucs05.EvmDisplay.make({
53-
address: "0x06627714f3F17a701f7074a12C02847a5D2Ca487",
54-
})
55-
const EU_STAKING_HUB = Ucs05.CosmosDisplay.make({
56-
address: "union1eueueueu9var4yhdruyzkjcsh74xzeug6ckyy60hs0vcqnzql2hq0lxc2f", // FIXME
61+
address: VIEM_ACCOUNT.address,
5762
})
5863

59-
const VIEM_ACCOUNT = privateKeyToAccount(
60-
process.env.KEY as any,
64+
const checkAndSubmitAllowance = pipe(
65+
Evm.readErc20Allowance(
66+
EU_ERC20.address,
67+
SENDER.address,
68+
UCS03_EVM.address,
69+
),
70+
Effect.flatMap((amount) =>
71+
Effect.if(amount < AMOUNT, {
72+
onTrue: () =>
73+
pipe(
74+
Effect.log(`Increasing allowance by ${AMOUNT - amount} for ${EU_ERC20.address}`),
75+
Effect.andThen(() =>
76+
pipe(
77+
Evm.increaseErc20Allowance(
78+
EU_ERC20.address,
79+
UCS03_EVM,
80+
AMOUNT - amount,
81+
),
82+
Effect.andThen(Evm.waitForTransactionReceipt),
83+
)
84+
),
85+
),
86+
onFalse: () =>
87+
Effect.log(`Allowance fulfilled by ${AMOUNT - amount} for ${EU_ERC20.address}`),
88+
})
89+
),
90+
)
91+
92+
const bytecode_base_checksum =
93+
"0xec827349ed4c1fec5a9c3462ff7c979d4c40e7aa43b16ed34469d04ff835f2a1" as const
94+
const canonical_zkgm = Ucs05.anyDisplayToCanonical(UCS03_ZKGM)
95+
const module_hash = "0x120970d812836f19888625587a4606a5ad23cef31c8684e601771552548fc6b9" as const
96+
97+
const instantiate2 = Effect.fn(
98+
function*(options: { path: bigint; channel: ChannelId; sender: Ucs05.AnyDisplay }) {
99+
const sender = yield* Ucs05.anyDisplayToZkgm(options.sender)
100+
const abi = [
101+
{
102+
name: "path",
103+
type: "uint256",
104+
internalType: "uint256",
105+
},
106+
{
107+
name: "channelId",
108+
type: "uint32",
109+
internalType: "uint32",
110+
},
111+
{
112+
name: "sender",
113+
type: "bytes",
114+
internalType: "bytes",
115+
},
116+
] as const
117+
118+
const args = [
119+
options.path,
120+
options.channel,
121+
sender,
122+
] as const
123+
124+
const encode = Effect.try(() =>
125+
encodeAbiParameters(
126+
abi,
127+
args,
128+
)
129+
)
130+
131+
const encoded = yield* encode
132+
133+
/**
134+
* n as BE rep
135+
*/
136+
const u64toBeBytes = (n: bigint) => {
137+
const buffer = new ArrayBuffer(8)
138+
const view = new DataView(buffer)
139+
view.setBigUint64(0, n)
140+
return new Uint8Array(view.buffer)
141+
}
142+
143+
const sha256 = (data: any) => globalThis.crypto.subtle.digest("SHA-256", data)
144+
145+
const salt = keccak256(encoded, "bytes")
146+
147+
const _args = [
148+
...fromHex(module_hash, "bytes"),
149+
...new TextEncoder().encode("wasm"),
150+
0, // null byte
151+
...u64toBeBytes(32n), // checksum len as 64-bit big endian bytes of int
152+
...fromHex(bytecode_base_checksum, "bytes"),
153+
...u64toBeBytes(32n), // creator canonical addr len
154+
...fromHex(canonical_zkgm, "bytes"),
155+
...u64toBeBytes(32n), // len
156+
...salt,
157+
...u64toBeBytes(0n),
158+
] as const
159+
160+
const data = Uint8Array.from(_args)
161+
162+
const r = yield* Effect.tryPromise(() => sha256(data))
163+
164+
const rBytes = bytesToHex(new Uint8Array(r))
165+
166+
const transform = Ucs05.Bech32FromCanonicalBytesWithPrefix("union")
167+
168+
const r2 = yield* Schema.decode(transform)(rBytes)
169+
170+
return Ucs05.CosmosDisplay.make({ address: r2 })
171+
},
61172
)
62173

63174
const sendUnbond = Effect.gen(function*() {
64175
const ethereumChain = yield* ChainRegistry.byUniversalId(ETHEREUM_CHAIN_ID)
65176
const unionChain = yield* ChainRegistry.byUniversalId(UNION_CHAIN_ID)
66-
67-
const eu_staking_hub = yield* Ucs05.anyDisplayToZkgm(EU_STAKING_HUB)
177+
const receiver = yield* instantiate2({
178+
path: 0n,
179+
channel: DESTINATION_CHANNEL_ID,
180+
sender: SENDER,
181+
})
68182

69183
const tokenOrder = yield* TokenOrder.make({
70184
source: ethereumChain,
71185
destination: unionChain,
72186
sender: SENDER,
73-
receiver: ON_ZKGM_CALL_PROXY,
74-
baseToken: U_ERC20,
187+
receiver,
188+
baseToken: EU_ERC20,
75189
baseAmount: AMOUNT,
76-
quoteToken: U_BANK,
190+
quoteToken: Token.Cw20.make({ address: EU_LST.address }),
77191
quoteAmount: AMOUNT,
78192
kind: "solve",
79-
metadata: U_TO_UNION_SOLVER_METADATA,
193+
metadata: EU_SOLVER_ON_UNION_METADATA,
80194
version: 2,
81195
})
82196

197+
const increaseAllowanceCall = yield* pipe(
198+
{
199+
increase_allowance: {
200+
spender: EU_STAKING_HUB.address,
201+
amount: AMOUNT,
202+
},
203+
} as const,
204+
Schema.encode(JsonFromBase64),
205+
Effect.map((msg) => ({
206+
wasm: {
207+
execute: {
208+
contract_addr: EU_LST.address,
209+
msg,
210+
funds: [],
211+
},
212+
},
213+
} as const)),
214+
)
215+
83216
const unbondCall = yield* pipe(
84-
{ amount: tokenOrder.quoteAmount } as const,
217+
{
218+
unbond: {
219+
staker: receiver.address,
220+
amount: tokenOrder.quoteAmount,
221+
},
222+
} as const,
85223
Schema.encode(JsonFromBase64),
86224
Effect.map((msg) => ({
87-
contract: eu_staking_hub,
88-
msg,
89-
funds: [],
90-
call_action: "call_proxy",
225+
wasm: {
226+
execute: {
227+
contract_addr: EU_STAKING_HUB.address,
228+
msg,
229+
funds: [],
230+
},
231+
},
91232
} as const)),
92-
Effect.flatMap(Schema.decode(HexFromJson)),
233+
)
234+
235+
const calls = yield* pipe(
236+
[
237+
increaseAllowanceCall,
238+
unbondCall,
239+
],
240+
Schema.decode(HexFromJson),
93241
Effect.map((contractCalldata) =>
94242
Call.make({
95243
sender: SENDER,
96244
eureka: false,
97-
contractAddress: ON_ZKGM_CALL_PROXY,
245+
contractAddress: receiver,
98246
contractCalldata,
99247
})
100248
),
101249
)
102250

103251
const batch = Batch.make([
104252
tokenOrder,
105-
unbondCall,
253+
calls,
106254
])
107255

108256
const request = ZkgmClientRequest.make({
109257
source: ethereumChain,
110258
destination: unionChain,
111259
channelId: SOURCE_CHANNEL_ID,
112-
ucs03Address: UCS03_MINTER.address,
260+
ucs03Address: UCS03_EVM.address,
113261
instruction: batch,
114262
})
115263

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

125273
yield* Effect.log("Receipt:", receipt)
126-
}).pipe(
274+
})
275+
276+
pipe(
277+
Effect.all([
278+
checkAndSubmitAllowance,
279+
sendUnbond,
280+
]),
127281
Effect.provide(EvmZkgmClient.layerWithoutWallet),
128282
Effect.provide(Evm.WalletClient.Live({
129283
account: VIEM_ACCOUNT,
@@ -143,8 +297,7 @@ const sendUnbond = Effect.gen(function*() {
143297
mode: "tty",
144298
}),
145299
)),
300+
Effect.runPromise,
146301
)
147-
148-
Effect.runPromise(sendUnbond)
149302
.then(console.log)
150303
.catch(console.error)

0 commit comments

Comments
 (0)