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