hermez-node/eth/wdelayer.go
eth/wdelayer.goRaw
1package eth
2
3import (
4 "context"
5 "fmt"
6 "math/big"
7 "strings"
8
9 "github.com/ethereum/go-ethereum"
10 "github.com/ethereum/go-ethereum/accounts/abi"
11 "github.com/ethereum/go-ethereum/accounts/abi/bind"
12 ethCommon "github.com/ethereum/go-ethereum/common"
13 "github.com/ethereum/go-ethereum/core/types"
14 "github.com/ethereum/go-ethereum/crypto"
15 "github.com/ethereum/go-ethereum/ethclient"
16 "github.com/hermeznetwork/hermez-node/common"
17 WithdrawalDelayer "github.com/hermeznetwork/hermez-node/eth/contracts/withdrawdelayer"
18 "github.com/hermeznetwork/hermez-node/log"
19)
20
21// DepositState is the state of Deposit
22type DepositState struct {
23 Amount *big.Int
24 DepositTimestamp uint64
25}
26
27// WDelayerEventDeposit is an event of the WithdrawalDelayer Smart Contract
28type WDelayerEventDeposit struct {
29 Owner ethCommon.Address
30 Token ethCommon.Address
31 Amount *big.Int
32 DepositTimestamp uint64
33}
34
35// WDelayerEventWithdraw is an event of the WithdrawalDelayer Smart Contract
36type WDelayerEventWithdraw struct {
37 Owner ethCommon.Address
38 Token ethCommon.Address
39 Amount *big.Int
40}
41
42// WDelayerEventEmergencyModeEnabled an event of the WithdrawalDelayer Smart Contract
43type WDelayerEventEmergencyModeEnabled struct {
44}
45
46// WDelayerEventNewWithdrawalDelay an event of the WithdrawalDelayer Smart Contract
47type WDelayerEventNewWithdrawalDelay struct {
48 WithdrawalDelay uint64
49}
50
51// WDelayerEventEscapeHatchWithdrawal an event of the WithdrawalDelayer Smart Contract
52type WDelayerEventEscapeHatchWithdrawal struct {
53 Who ethCommon.Address
54 To ethCommon.Address
55 Token ethCommon.Address
56 Amount *big.Int
57}
58
59// WDelayerEventNewHermezKeeperAddress an event of the WithdrawalDelayer Smart Contract
60type WDelayerEventNewHermezKeeperAddress struct {
61 NewHermezKeeperAddress ethCommon.Address
62}
63
64// WDelayerEventNewWhiteHackGroupAddress an event of the WithdrawalDelayer Smart Contract
65type WDelayerEventNewWhiteHackGroupAddress struct {
66 NewWhiteHackGroupAddress ethCommon.Address
67}
68
69// WDelayerEventNewHermezGovernanceDAOAddress an event of the WithdrawalDelayer Smart Contract
70type WDelayerEventNewHermezGovernanceDAOAddress struct {
71 NewHermezGovernanceDAOAddress ethCommon.Address
72}
73
74// WDelayerEvents is the lis of events in a block of the WithdrawalDelayer Smart Contract
75type WDelayerEvents struct {
76 Deposit []WDelayerEventDeposit
77 Withdraw []WDelayerEventWithdraw
78 EmergencyModeEnabled []WDelayerEventEmergencyModeEnabled
79 NewWithdrawalDelay []WDelayerEventNewWithdrawalDelay
80 EscapeHatchWithdrawal []WDelayerEventEscapeHatchWithdrawal
81 NewHermezKeeperAddress []WDelayerEventNewHermezKeeperAddress
82 NewWhiteHackGroupAddress []WDelayerEventNewWhiteHackGroupAddress
83 NewHermezGovernanceDAOAddress []WDelayerEventNewHermezGovernanceDAOAddress
84}
85
86// NewWDelayerEvents creates an empty WDelayerEvents with the slices initialized.
87func NewWDelayerEvents() WDelayerEvents {
88 return WDelayerEvents{
89 Deposit: make([]WDelayerEventDeposit, 0),
90 Withdraw: make([]WDelayerEventWithdraw, 0),
91 EmergencyModeEnabled: make([]WDelayerEventEmergencyModeEnabled, 0),
92 NewWithdrawalDelay: make([]WDelayerEventNewWithdrawalDelay, 0),
93 EscapeHatchWithdrawal: make([]WDelayerEventEscapeHatchWithdrawal, 0),
94 NewHermezKeeperAddress: make([]WDelayerEventNewHermezKeeperAddress, 0),
95 NewWhiteHackGroupAddress: make([]WDelayerEventNewWhiteHackGroupAddress, 0),
96 NewHermezGovernanceDAOAddress: make([]WDelayerEventNewHermezGovernanceDAOAddress, 0),
97 }
98}
99
100// WDelayerInterface is the inteface to WithdrawalDelayer Smart Contract
101type WDelayerInterface interface {
102 //
103 // Smart Contract Methods
104 //
105
106 WDelayerGetHermezGovernanceDAOAddress() (*ethCommon.Address, error)
107 WDelayerSetHermezGovernanceDAOAddress(newAddress ethCommon.Address) (*types.Transaction, error)
108 WDelayerGetHermezKeeperAddress() (*ethCommon.Address, error)
109 WDelayerSetHermezKeeperAddress(newAddress ethCommon.Address) (*types.Transaction, error)
110 WDelayerGetWhiteHackGroupAddress() (*ethCommon.Address, error)
111 WDelayerSetWhiteHackGroupAddress(newAddress ethCommon.Address) (*types.Transaction, error)
112 WDelayerIsEmergencyMode() (bool, error)
113 WDelayerGetWithdrawalDelay() (*big.Int, error)
114 WDelayerGetEmergencyModeStartingTime() (*big.Int, error)
115 WDelayerEnableEmergencyMode() (*types.Transaction, error)
116 WDelayerChangeWithdrawalDelay(newWithdrawalDelay uint64) (*types.Transaction, error)
117 WDelayerDepositInfo(owner, token ethCommon.Address) (*big.Int, uint64)
118 WDelayerDeposit(onwer, token ethCommon.Address, amount *big.Int) (*types.Transaction, error)
119 WDelayerWithdrawal(owner, token ethCommon.Address) (*types.Transaction, error)
120 WDelayerEscapeHatchWithdrawal(to, token ethCommon.Address, amount *big.Int) (*types.Transaction, error)
121
122 WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents, *ethCommon.Hash, error)
123 WDelayerConstants() (*common.WDelayerConstants, error)
124}
125
126//
127// Implementation
128//
129
130// WDelayerClient is the implementation of the interface to the WithdrawDelayer Smart Contract in ethereum.
131type WDelayerClient struct {
132 client *EthereumClient
133 address ethCommon.Address
134 wdelayer *WithdrawalDelayer.WithdrawalDelayer
135 contractAbi abi.ABI
136}
137
138// NewWDelayerClient creates a new WDelayerClient
139func NewWDelayerClient(client *EthereumClient, address ethCommon.Address) (*WDelayerClient, error) {
140 contractAbi, err := abi.JSON(strings.NewReader(string(WithdrawalDelayer.WithdrawalDelayerABI)))
141 if err != nil {
142 return nil, err
143 }
144 wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(address, client.Client())
145 if err != nil {
146 return nil, err
147 }
148 return &WDelayerClient{
149 client: client,
150 address: address,
151 wdelayer: wdelayer,
152 contractAbi: contractAbi,
153 }, nil
154}
155
156// WDelayerGetHermezGovernanceDAOAddress is the interface to call the smart contract function
157func (c *WDelayerClient) WDelayerGetHermezGovernanceDAOAddress() (hermezGovernanceDAOAddress *ethCommon.Address, err error) {
158 var _hermezGovernanceDAOAddress ethCommon.Address
159 if err := c.client.Call(func(ec *ethclient.Client) error {
160 _hermezGovernanceDAOAddress, err = c.wdelayer.GetHermezGovernanceDAOAddress(nil)
161 return err
162 }); err != nil {
163 return nil, err
164 }
165 return &_hermezGovernanceDAOAddress, nil
166}
167
168// WDelayerSetHermezGovernanceDAOAddress is the interface to call the smart contract function
169func (c *WDelayerClient) WDelayerSetHermezGovernanceDAOAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
170 if tx, err = c.client.CallAuth(
171 0,
172 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
173 return c.wdelayer.SetHermezGovernanceDAOAddress(auth, newAddress)
174 },
175 ); err != nil {
176 return nil, fmt.Errorf("Failed setting hermezGovernanceDAOAddress: %w", err)
177 }
178 return tx, nil
179}
180
181// WDelayerGetHermezKeeperAddress is the interface to call the smart contract function
182func (c *WDelayerClient) WDelayerGetHermezKeeperAddress() (hermezKeeperAddress *ethCommon.Address, err error) {
183 var _hermezKeeperAddress ethCommon.Address
184 if err := c.client.Call(func(ec *ethclient.Client) error {
185 _hermezKeeperAddress, err = c.wdelayer.GetHermezKeeperAddress(nil)
186 return err
187 }); err != nil {
188 return nil, err
189 }
190 return &_hermezKeeperAddress, nil
191}
192
193// WDelayerSetHermezKeeperAddress is the interface to call the smart contract function
194func (c *WDelayerClient) WDelayerSetHermezKeeperAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
195 if tx, err = c.client.CallAuth(
196 0,
197 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
198 return c.wdelayer.SetHermezKeeperAddress(auth, newAddress)
199 },
200 ); err != nil {
201 return nil, fmt.Errorf("Failed setting hermezKeeperAddress: %w", err)
202 }
203 return tx, nil
204}
205
206// WDelayerGetWhiteHackGroupAddress is the interface to call the smart contract function
207func (c *WDelayerClient) WDelayerGetWhiteHackGroupAddress() (whiteHackGroupAddress *ethCommon.Address, err error) {
208 var _whiteHackGroupAddress ethCommon.Address
209 if err := c.client.Call(func(ec *ethclient.Client) error {
210 _whiteHackGroupAddress, err = c.wdelayer.GetWhiteHackGroupAddress(nil)
211 return err
212 }); err != nil {
213 return nil, err
214 }
215 return &_whiteHackGroupAddress, nil
216}
217
218// WDelayerSetWhiteHackGroupAddress is the interface to call the smart contract function
219func (c *WDelayerClient) WDelayerSetWhiteHackGroupAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
220 if tx, err = c.client.CallAuth(
221 0,
222 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
223 return c.wdelayer.SetWhiteHackGroupAddress(auth, newAddress)
224 },
225 ); err != nil {
226 return nil, fmt.Errorf("Failed setting whiteHackGroupAddress: %w", err)
227 }
228 return tx, nil
229}
230
231// WDelayerIsEmergencyMode is the interface to call the smart contract function
232func (c *WDelayerClient) WDelayerIsEmergencyMode() (ermergencyMode bool, err error) {
233 if err := c.client.Call(func(ec *ethclient.Client) error {
234 ermergencyMode, err = c.wdelayer.IsEmergencyMode(nil)
235 return err
236 }); err != nil {
237 return false, err
238 }
239 return ermergencyMode, nil
240}
241
242// WDelayerGetWithdrawalDelay is the interface to call the smart contract function
243func (c *WDelayerClient) WDelayerGetWithdrawalDelay() (withdrawalDelay *big.Int, err error) {
244 if err := c.client.Call(func(ec *ethclient.Client) error {
245 withdrawalDelay, err = c.wdelayer.GetWithdrawalDelay(nil)
246 return err
247 }); err != nil {
248 return nil, err
249 }
250 return withdrawalDelay, nil
251}
252
253// WDelayerGetEmergencyModeStartingTime is the interface to call the smart contract function
254func (c *WDelayerClient) WDelayerGetEmergencyModeStartingTime() (emergencyModeStartingTime *big.Int, err error) {
255 if err := c.client.Call(func(ec *ethclient.Client) error {
256 emergencyModeStartingTime, err = c.wdelayer.GetEmergencyModeStartingTime(nil)
257 return err
258 }); err != nil {
259 return nil, err
260 }
261 return emergencyModeStartingTime, nil
262}
263
264// WDelayerEnableEmergencyMode is the interface to call the smart contract function
265func (c *WDelayerClient) WDelayerEnableEmergencyMode() (tx *types.Transaction, err error) {
266 if tx, err = c.client.CallAuth(
267 0,
268 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
269 return c.wdelayer.EnableEmergencyMode(auth)
270 },
271 ); err != nil {
272 return nil, fmt.Errorf("Failed setting enable emergency mode: %w", err)
273 }
274 return tx, nil
275}
276
277// WDelayerChangeWithdrawalDelay is the interface to call the smart contract function
278func (c *WDelayerClient) WDelayerChangeWithdrawalDelay(newWithdrawalDelay uint64) (tx *types.Transaction, err error) {
279 if tx, err = c.client.CallAuth(
280 0,
281 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
282 return c.wdelayer.ChangeWithdrawalDelay(auth, newWithdrawalDelay)
283 },
284 ); err != nil {
285 return nil, fmt.Errorf("Failed setting withdrawal delay: %w", err)
286 }
287 return tx, nil
288}
289
290// WDelayerDepositInfo is the interface to call the smart contract function
291func (c *WDelayerClient) WDelayerDepositInfo(owner, token ethCommon.Address) (depositInfo DepositState, err error) {
292 if err := c.client.Call(func(ec *ethclient.Client) error {
293 amount, depositTimestamp, err := c.wdelayer.DepositInfo(nil, owner, token)
294 depositInfo.Amount = amount
295 depositInfo.DepositTimestamp = depositTimestamp
296 return err
297 }); err != nil {
298 return depositInfo, err
299 }
300 return depositInfo, nil
301}
302
303// WDelayerDeposit is the interface to call the smart contract function
304func (c *WDelayerClient) WDelayerDeposit(owner, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
305 if tx, err = c.client.CallAuth(
306 0,
307 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
308 return c.wdelayer.Deposit(auth, owner, token, amount)
309 },
310 ); err != nil {
311 return nil, fmt.Errorf("Failed deposit: %w", err)
312 }
313 return tx, nil
314}
315
316// WDelayerWithdrawal is the interface to call the smart contract function
317func (c *WDelayerClient) WDelayerWithdrawal(owner, token ethCommon.Address) (tx *types.Transaction, err error) {
318 if tx, err = c.client.CallAuth(
319 0,
320 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
321 return c.wdelayer.Withdrawal(auth, owner, token)
322 },
323 ); err != nil {
324 return nil, fmt.Errorf("Failed withdrawal: %w", err)
325 }
326 return tx, nil
327}
328
329// WDelayerEscapeHatchWithdrawal is the interface to call the smart contract function
330func (c *WDelayerClient) WDelayerEscapeHatchWithdrawal(to, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
331 if tx, err = c.client.CallAuth(
332 0,
333 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
334 return c.wdelayer.EscapeHatchWithdrawal(auth, to, token, amount)
335 },
336 ); err != nil {
337 return nil, fmt.Errorf("Failed escapeHatchWithdrawal: %w", err)
338 }
339 return tx, nil
340}
341
342// WDelayerConstants returns the Constants of the WDelayer Smart Contract
343func (c *WDelayerClient) WDelayerConstants() (constants common.WDelayerConstants, err error) {
344 if err := c.client.Call(func(ec *ethclient.Client) error {
345 constants.MaxWithdrawalDelay, err = c.wdelayer.MAXWITHDRAWALDELAY(nil)
346 if err != nil {
347 return err
348 }
349 constants.MaxEmergencyModeTime, err = c.wdelayer.MAXEMERGENCYMODETIME(nil)
350 if err != nil {
351 return err
352 }
353 constants.HermezRollup, err = c.wdelayer.HermezRollupAddress(nil)
354 if err != nil {
355 return err
356 }
357 return err
358 }); err != nil {
359 return constants, err
360 }
361 return constants, nil
362}
363
364var (
365 logWDelayerDeposit = crypto.Keccak256Hash([]byte("Deposit(address,address,uint192,uint64)"))
366 logWDelayerWithdraw = crypto.Keccak256Hash([]byte("Withdraw(address,address,uint192)"))
367 logWDelayerEmergencyModeEnabled = crypto.Keccak256Hash([]byte("EmergencyModeEnabled()"))
368 logWDelayerNewWithdrawalDelay = crypto.Keccak256Hash([]byte("NewWithdrawalDelay(uint64)"))
369 logWDelayerEscapeHatchWithdrawal = crypto.Keccak256Hash([]byte("EscapeHatchWithdrawal(address,address,address,uint256)"))
370 logWDelayerNewHermezKeeperAddress = crypto.Keccak256Hash([]byte("NewHermezKeeperAddress(address)"))
371 logWDelayerNewWhiteHackGroupAddress = crypto.Keccak256Hash([]byte("NewWhiteHackGroupAddress(address)"))
372 logWDelayerNewHermezGovernanceDAOAddress = crypto.Keccak256Hash([]byte("NewHermezGovernanceDAOAddress(address)"))
373)
374
375// WDelayerEventsByBlock returns the events in a block that happened in the
376// WDelayer Smart Contract and the blockHash where the eents happened. If
377// there are no events in that block, blockHash is nil.
378func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents, *ethCommon.Hash, error) {
379 var wdelayerEvents WDelayerEvents
380 var blockHash ethCommon.Hash
381
382 query := ethereum.FilterQuery{
383 FromBlock: big.NewInt(blockNum),
384 ToBlock: big.NewInt(blockNum),
385 Addresses: []ethCommon.Address{
386 c.address,
387 },
388 BlockHash: nil,
389 Topics: [][]ethCommon.Hash{},
390 }
391
392 logs, err := c.client.client.FilterLogs(context.Background(), query)
393 if err != nil {
394 return nil, nil, err
395 }
396 if len(logs) > 0 {
397 blockHash = logs[0].BlockHash
398 }
399 for _, vLog := range logs {
400 if vLog.BlockHash != blockHash {
401 log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String())
402 return nil, nil, ErrBlockHashMismatchEvent
403 }
404 switch vLog.Topics[0] {
405 case logWDelayerDeposit:
406 var deposit WDelayerEventDeposit
407 err := c.contractAbi.Unpack(&deposit, "Deposit", vLog.Data)
408 if err != nil {
409 return nil, nil, err
410 }
411 deposit.Owner = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
412 deposit.Token = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
413 wdelayerEvents.Deposit = append(wdelayerEvents.Deposit, deposit)
414
415 case logWDelayerWithdraw:
416 var withdraw WDelayerEventWithdraw
417 err := c.contractAbi.Unpack(&withdraw, "Withdraw", vLog.Data)
418 if err != nil {
419 return nil, nil, err
420 }
421 withdraw.Token = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
422 withdraw.Owner = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
423 wdelayerEvents.Withdraw = append(wdelayerEvents.Withdraw, withdraw)
424
425 case logWDelayerEmergencyModeEnabled:
426 var emergencyModeEnabled WDelayerEventEmergencyModeEnabled
427 wdelayerEvents.EmergencyModeEnabled = append(wdelayerEvents.EmergencyModeEnabled, emergencyModeEnabled)
428
429 case logWDelayerNewWithdrawalDelay:
430 var withdrawalDelay WDelayerEventNewWithdrawalDelay
431 err := c.contractAbi.Unpack(&withdrawalDelay, "NewWithdrawalDelay", vLog.Data)
432 if err != nil {
433 return nil, nil, err
434 }
435 wdelayerEvents.NewWithdrawalDelay = append(wdelayerEvents.NewWithdrawalDelay, withdrawalDelay)
436
437 case logWDelayerEscapeHatchWithdrawal:
438 var escapeHatchWithdrawal WDelayerEventEscapeHatchWithdrawal
439 err := c.contractAbi.Unpack(&escapeHatchWithdrawal, "EscapeHatchWithdrawal", vLog.Data)
440 if err != nil {
441 return nil, nil, err
442 }
443 escapeHatchWithdrawal.Who = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
444 escapeHatchWithdrawal.To = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
445 escapeHatchWithdrawal.Token = ethCommon.BytesToAddress(vLog.Topics[3].Bytes())
446 wdelayerEvents.EscapeHatchWithdrawal = append(wdelayerEvents.EscapeHatchWithdrawal, escapeHatchWithdrawal)
447
448 case logWDelayerNewHermezKeeperAddress:
449 var keeperAddress WDelayerEventNewHermezKeeperAddress
450 err := c.contractAbi.Unpack(&keeperAddress, "NewHermezKeeperAddress", vLog.Data)
451 if err != nil {
452 return nil, nil, err
453 }
454 wdelayerEvents.NewHermezKeeperAddress = append(wdelayerEvents.NewHermezKeeperAddress, keeperAddress)
455
456 case logWDelayerNewWhiteHackGroupAddress:
457 var whiteHackGroupAddress WDelayerEventNewWhiteHackGroupAddress
458 err := c.contractAbi.Unpack(&whiteHackGroupAddress, "NewWhiteHackGroupAddress", vLog.Data)
459 if err != nil {
460 return nil, nil, err
461 }
462 wdelayerEvents.NewWhiteHackGroupAddress = append(wdelayerEvents.NewWhiteHackGroupAddress, whiteHackGroupAddress)
463
464 case logWDelayerNewHermezGovernanceDAOAddress:
465 var governanceDAOAddress WDelayerEventNewHermezGovernanceDAOAddress
466 err := c.contractAbi.Unpack(&governanceDAOAddress, "NewHermezGovernanceDAOAddress", vLog.Data)
467 if err != nil {
468 return nil, nil, err
469 }
470 wdelayerEvents.NewHermezGovernanceDAOAddress = append(wdelayerEvents.NewHermezGovernanceDAOAddress, governanceDAOAddress)
471 }
472 }
473 return &wdelayerEvents, &blockHash, nil
474}