arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
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}