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