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