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