@@ -13,6 +13,7 @@ if (typeof BigInt.prototype.toJSON !== "function") {
13
13
import {
14
14
Batch ,
15
15
Call ,
16
+ Token ,
16
17
TokenOrder ,
17
18
Ucs05 ,
18
19
ZkgmClient ,
@@ -22,16 +23,16 @@ import {
22
23
import { Evm , EvmZkgmClient } from "@unionlabs/sdk-evm"
23
24
import { ChainRegistry } from "@unionlabs/sdk/ChainRegistry"
24
25
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 ,
29
30
} from "@unionlabs/sdk/Constants"
30
31
import { UniversalChainId } from "@unionlabs/sdk/schema/chain"
31
32
import { ChannelId } from "@unionlabs/sdk/schema/channel"
32
33
import { HexFromJson } from "@unionlabs/sdk/schema/hex"
33
34
import { Effect , Logger , pipe , Schema } from "effect"
34
- import { http } from "viem"
35
+ import { bytesToHex , encodeAbiParameters , fromHex , http , keccak256 } from "viem"
35
36
import { privateKeyToAccount } from "viem/accounts"
36
37
import { holesky } from "viem/chains"
37
38
@@ -40,76 +41,223 @@ const JsonFromBase64 = Schema.compose(
40
41
Schema . parseJson ( ) ,
41
42
)
42
43
43
- const AMOUNT = 1n
44
+ const AMOUNT = 5n
44
45
const ETHEREUM_CHAIN_ID = UniversalChainId . make ( "ethereum.17000" )
45
46
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 ( {
48
53
address : "0x5fbe74a283f7954f10aa04c2edf55578811aeb03" ,
49
54
} )
50
55
const VIEM_CHAIN = holesky
51
56
const RPC_URL = "https://rpc.17000.ethereum.chain.kitchen"
57
+ const VIEM_ACCOUNT = privateKeyToAccount (
58
+ process . env . KEY as any ,
59
+ )
52
60
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 ,
57
62
} )
58
63
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
+ } ,
61
172
)
62
173
63
174
const sendUnbond = Effect . gen ( function * ( ) {
64
175
const ethereumChain = yield * ChainRegistry . byUniversalId ( ETHEREUM_CHAIN_ID )
65
176
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
+ } )
68
182
69
183
const tokenOrder = yield * TokenOrder . make ( {
70
184
source : ethereumChain ,
71
185
destination : unionChain ,
72
186
sender : SENDER ,
73
- receiver : ON_ZKGM_CALL_PROXY ,
74
- baseToken : U_ERC20 ,
187
+ receiver,
188
+ baseToken : EU_ERC20 ,
75
189
baseAmount : AMOUNT ,
76
- quoteToken : U_BANK ,
190
+ quoteToken : Token . Cw20 . make ( { address : EU_LST . address } ) ,
77
191
quoteAmount : AMOUNT ,
78
192
kind : "solve" ,
79
- metadata : U_TO_UNION_SOLVER_METADATA ,
193
+ metadata : EU_SOLVER_ON_UNION_METADATA ,
80
194
version : 2 ,
81
195
} )
82
196
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
+
83
216
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 ,
85
223
Schema . encode ( JsonFromBase64 ) ,
86
224
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
+ } ,
91
232
} 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 ) ,
93
241
Effect . map ( ( contractCalldata ) =>
94
242
Call . make ( {
95
243
sender : SENDER ,
96
244
eureka : false ,
97
- contractAddress : ON_ZKGM_CALL_PROXY ,
245
+ contractAddress : receiver ,
98
246
contractCalldata,
99
247
} )
100
248
) ,
101
249
)
102
250
103
251
const batch = Batch . make ( [
104
252
tokenOrder ,
105
- unbondCall ,
253
+ calls ,
106
254
] )
107
255
108
256
const request = ZkgmClientRequest . make ( {
109
257
source : ethereumChain ,
110
258
destination : unionChain ,
111
259
channelId : SOURCE_CHANNEL_ID ,
112
- ucs03Address : UCS03_MINTER . address ,
260
+ ucs03Address : UCS03_EVM . address ,
113
261
instruction : batch ,
114
262
} )
115
263
@@ -123,7 +271,13 @@ const sendUnbond = Effect.gen(function*() {
123
271
)
124
272
125
273
yield * Effect . log ( "Receipt:" , receipt )
126
- } ) . pipe (
274
+ } )
275
+
276
+ pipe (
277
+ Effect . all ( [
278
+ checkAndSubmitAllowance ,
279
+ sendUnbond ,
280
+ ] ) ,
127
281
Effect . provide ( EvmZkgmClient . layerWithoutWallet ) ,
128
282
Effect . provide ( Evm . WalletClient . Live ( {
129
283
account : VIEM_ACCOUNT ,
@@ -143,8 +297,7 @@ const sendUnbond = Effect.gen(function*() {
143
297
mode : "tty" ,
144
298
} ) ,
145
299
) ) ,
300
+ Effect . runPromise ,
146
301
)
147
-
148
- Effect . runPromise ( sendUnbond )
149
302
. then ( console . log )
150
303
. catch ( console . error )
0 commit comments