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