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) (depositInfo DepositState, err error)
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 constants = new(common.WDelayerConstants)
345 if err := c.client.Call(func(ec *ethclient.Client) error {
346 constants.MaxWithdrawalDelay, err = c.wdelayer.MAXWITHDRAWALDELAY(nil)
347 if err != nil {
348 return err
349 }
350 constants.MaxEmergencyModeTime, err = c.wdelayer.MAXEMERGENCYMODETIME(nil)
351 if err != nil {
352 return err
353 }
354 constants.HermezRollup, err = c.wdelayer.HermezRollupAddress(nil)
355 if err != nil {
356 return err
357 }
358 return err
359 }); err != nil {
360 return constants, err
361 }
362 return constants, nil
363}
364
365var (
366 logWDelayerDeposit = crypto.Keccak256Hash([]byte("Deposit(address,address,uint192,uint64)"))
367 logWDelayerWithdraw = crypto.Keccak256Hash([]byte("Withdraw(address,address,uint192)"))
368 logWDelayerEmergencyModeEnabled = crypto.Keccak256Hash([]byte("EmergencyModeEnabled()"))
369 logWDelayerNewWithdrawalDelay = crypto.Keccak256Hash([]byte("NewWithdrawalDelay(uint64)"))
370 logWDelayerEscapeHatchWithdrawal = crypto.Keccak256Hash([]byte("EscapeHatchWithdrawal(address,address,address,uint256)"))
371 logWDelayerNewHermezKeeperAddress = crypto.Keccak256Hash([]byte("NewHermezKeeperAddress(address)"))
372 logWDelayerNewWhiteHackGroupAddress = crypto.Keccak256Hash([]byte("NewWhiteHackGroupAddress(address)"))
373 logWDelayerNewHermezGovernanceDAOAddress = crypto.Keccak256Hash([]byte("NewHermezGovernanceDAOAddress(address)"))
374)
375
376// WDelayerEventsByBlock returns the events in a block that happened in the
377// WDelayer Smart Contract and the blockHash where the eents happened. If
378// there are no events in that block, blockHash is nil.
379func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents, *ethCommon.Hash, error) {
380 var wdelayerEvents WDelayerEvents
381 var blockHash *ethCommon.Hash
382
383 query := ethereum.FilterQuery{
384 FromBlock: big.NewInt(blockNum),
385 ToBlock: big.NewInt(blockNum),
386 Addresses: []ethCommon.Address{
387 c.address,
388 },
389 BlockHash: nil,
390 Topics: [][]ethCommon.Hash{},
391 }
392
393 logs, err := c.client.client.FilterLogs(context.Background(), query)
394 if err != nil {
395 return nil, nil, err
396 }
397 if len(logs) > 0 {
398 blockHash = &logs[0].BlockHash
399 }
400 for _, vLog := range logs {
401 if vLog.BlockHash != *blockHash {
402 log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String())
403 return nil, nil, ErrBlockHashMismatchEvent
404 }
405 switch vLog.Topics[0] {
406 case logWDelayerDeposit:
407 var deposit WDelayerEventDeposit
408 err := c.contractAbi.Unpack(&deposit, "Deposit", vLog.Data)
409 if err != nil {
410 return nil, nil, err
411 }
412 deposit.Owner = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
413 deposit.Token = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
414 wdelayerEvents.Deposit = append(wdelayerEvents.Deposit, deposit)
415
416 case logWDelayerWithdraw:
417 var withdraw WDelayerEventWithdraw
418 err := c.contractAbi.Unpack(&withdraw, "Withdraw", vLog.Data)
419 if err != nil {
420 return nil, nil, err
421 }
422 withdraw.Token = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
423 withdraw.Owner = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
424 wdelayerEvents.Withdraw = append(wdelayerEvents.Withdraw, withdraw)
425
426 case logWDelayerEmergencyModeEnabled:
427 var emergencyModeEnabled WDelayerEventEmergencyModeEnabled
428 wdelayerEvents.EmergencyModeEnabled = append(wdelayerEvents.EmergencyModeEnabled, emergencyModeEnabled)
429
430 case logWDelayerNewWithdrawalDelay:
431 var withdrawalDelay WDelayerEventNewWithdrawalDelay
432 err := c.contractAbi.Unpack(&withdrawalDelay, "NewWithdrawalDelay", vLog.Data)
433 if err != nil {
434 return nil, nil, err
435 }
436 wdelayerEvents.NewWithdrawalDelay = append(wdelayerEvents.NewWithdrawalDelay, withdrawalDelay)
437
438 case logWDelayerEscapeHatchWithdrawal:
439 var escapeHatchWithdrawal WDelayerEventEscapeHatchWithdrawal
440 err := c.contractAbi.Unpack(&escapeHatchWithdrawal, "EscapeHatchWithdrawal", vLog.Data)
441 if err != nil {
442 return nil, nil, err
443 }
444 escapeHatchWithdrawal.Who = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
445 escapeHatchWithdrawal.To = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
446 escapeHatchWithdrawal.Token = ethCommon.BytesToAddress(vLog.Topics[3].Bytes())
447 wdelayerEvents.EscapeHatchWithdrawal = append(wdelayerEvents.EscapeHatchWithdrawal, escapeHatchWithdrawal)
448
449 case logWDelayerNewHermezKeeperAddress:
450 var keeperAddress WDelayerEventNewHermezKeeperAddress
451 err := c.contractAbi.Unpack(&keeperAddress, "NewHermezKeeperAddress", vLog.Data)
452 if err != nil {
453 return nil, nil, err
454 }
455 wdelayerEvents.NewHermezKeeperAddress = append(wdelayerEvents.NewHermezKeeperAddress, keeperAddress)
456
457 case logWDelayerNewWhiteHackGroupAddress:
458 var whiteHackGroupAddress WDelayerEventNewWhiteHackGroupAddress
459 err := c.contractAbi.Unpack(&whiteHackGroupAddress, "NewWhiteHackGroupAddress", vLog.Data)
460 if err != nil {
461 return nil, nil, err
462 }
463 wdelayerEvents.NewWhiteHackGroupAddress = append(wdelayerEvents.NewWhiteHackGroupAddress, whiteHackGroupAddress)
464
465 case logWDelayerNewHermezGovernanceDAOAddress:
466 var governanceDAOAddress WDelayerEventNewHermezGovernanceDAOAddress
467 err := c.contractAbi.Unpack(&governanceDAOAddress, "NewHermezGovernanceDAOAddress", vLog.Data)
468 if err != nil {
469 return nil, nil, err
470 }
471 wdelayerEvents.NewHermezGovernanceDAOAddress = append(wdelayerEvents.NewHermezGovernanceDAOAddress, governanceDAOAddress)
472 }
473 }
474 return &wdelayerEvents, blockHash, nil
475}