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) (depositInfo DepositState, err error)
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	constants = new(common.WDelayerConstants)
345	if err := c.client.Call(func(ec *ethclient.Client) error {
346		constants.MaxWithdrawalDelay, err = c.wdelayer.MAXWITHDRAWALDELAY(nil)
347		if err != nil {
348			return err
349		}
350		constants.MaxEmergencyModeTime, err = c.wdelayer.MAXEMERGENCYMODETIME(nil)
351		if err != nil {
352			return err
353		}
354		constants.HermezRollup, err = c.wdelayer.HermezRollupAddress(nil)
355		if err != nil {
356			return err
357		}
358		return err
359	}); err != nil {
360		return constants, err
361	}
362	return constants, nil
363}
364
365var (
366	logWDelayerDeposit                       = crypto.Keccak256Hash([]byte("Deposit(address,address,uint192,uint64)"))
367	logWDelayerWithdraw                      = crypto.Keccak256Hash([]byte("Withdraw(address,address,uint192)"))
368	logWDelayerEmergencyModeEnabled          = crypto.Keccak256Hash([]byte("EmergencyModeEnabled()"))
369	logWDelayerNewWithdrawalDelay            = crypto.Keccak256Hash([]byte("NewWithdrawalDelay(uint64)"))
370	logWDelayerEscapeHatchWithdrawal         = crypto.Keccak256Hash([]byte("EscapeHatchWithdrawal(address,address,address,uint256)"))
371	logWDelayerNewHermezKeeperAddress        = crypto.Keccak256Hash([]byte("NewHermezKeeperAddress(address)"))
372	logWDelayerNewWhiteHackGroupAddress      = crypto.Keccak256Hash([]byte("NewWhiteHackGroupAddress(address)"))
373	logWDelayerNewHermezGovernanceDAOAddress = crypto.Keccak256Hash([]byte("NewHermezGovernanceDAOAddress(address)"))
374)
375
376// WDelayerEventsByBlock returns the events in a block that happened in the
377// WDelayer Smart Contract and the blockHash where the eents happened.  If
378// there are no events in that block, blockHash is nil.
379func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents, *ethCommon.Hash, error) {
380	var wdelayerEvents WDelayerEvents
381	var blockHash *ethCommon.Hash
382
383	query := ethereum.FilterQuery{
384		FromBlock: big.NewInt(blockNum),
385		ToBlock:   big.NewInt(blockNum),
386		Addresses: []ethCommon.Address{
387			c.address,
388		},
389		BlockHash: nil,
390		Topics:    [][]ethCommon.Hash{},
391	}
392
393	logs, err := c.client.client.FilterLogs(context.Background(), query)
394	if err != nil {
395		return nil, nil, err
396	}
397	if len(logs) > 0 {
398		blockHash = &logs[0].BlockHash
399	}
400	for _, vLog := range logs {
401		if vLog.BlockHash != *blockHash {
402			log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String())
403			return nil, nil, ErrBlockHashMismatchEvent
404		}
405		switch vLog.Topics[0] {
406		case logWDelayerDeposit:
407			var deposit WDelayerEventDeposit
408			err := c.contractAbi.Unpack(&deposit, "Deposit", vLog.Data)
409			if err != nil {
410				return nil, nil, err
411			}
412			deposit.Owner = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
413			deposit.Token = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
414			wdelayerEvents.Deposit = append(wdelayerEvents.Deposit, deposit)
415
416		case logWDelayerWithdraw:
417			var withdraw WDelayerEventWithdraw
418			err := c.contractAbi.Unpack(&withdraw, "Withdraw", vLog.Data)
419			if err != nil {
420				return nil, nil, err
421			}
422			withdraw.Token = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
423			withdraw.Owner = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
424			wdelayerEvents.Withdraw = append(wdelayerEvents.Withdraw, withdraw)
425
426		case logWDelayerEmergencyModeEnabled:
427			var emergencyModeEnabled WDelayerEventEmergencyModeEnabled
428			wdelayerEvents.EmergencyModeEnabled = append(wdelayerEvents.EmergencyModeEnabled, emergencyModeEnabled)
429
430		case logWDelayerNewWithdrawalDelay:
431			var withdrawalDelay WDelayerEventNewWithdrawalDelay
432			err := c.contractAbi.Unpack(&withdrawalDelay, "NewWithdrawalDelay", vLog.Data)
433			if err != nil {
434				return nil, nil, err
435			}
436			wdelayerEvents.NewWithdrawalDelay = append(wdelayerEvents.NewWithdrawalDelay, withdrawalDelay)
437
438		case logWDelayerEscapeHatchWithdrawal:
439			var escapeHatchWithdrawal WDelayerEventEscapeHatchWithdrawal
440			err := c.contractAbi.Unpack(&escapeHatchWithdrawal, "EscapeHatchWithdrawal", vLog.Data)
441			if err != nil {
442				return nil, nil, err
443			}
444			escapeHatchWithdrawal.Who = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
445			escapeHatchWithdrawal.To = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
446			escapeHatchWithdrawal.Token = ethCommon.BytesToAddress(vLog.Topics[3].Bytes())
447			wdelayerEvents.EscapeHatchWithdrawal = append(wdelayerEvents.EscapeHatchWithdrawal, escapeHatchWithdrawal)
448
449		case logWDelayerNewHermezKeeperAddress:
450			var keeperAddress WDelayerEventNewHermezKeeperAddress
451			err := c.contractAbi.Unpack(&keeperAddress, "NewHermezKeeperAddress", vLog.Data)
452			if err != nil {
453				return nil, nil, err
454			}
455			wdelayerEvents.NewHermezKeeperAddress = append(wdelayerEvents.NewHermezKeeperAddress, keeperAddress)
456
457		case logWDelayerNewWhiteHackGroupAddress:
458			var whiteHackGroupAddress WDelayerEventNewWhiteHackGroupAddress
459			err := c.contractAbi.Unpack(&whiteHackGroupAddress, "NewWhiteHackGroupAddress", vLog.Data)
460			if err != nil {
461				return nil, nil, err
462			}
463			wdelayerEvents.NewWhiteHackGroupAddress = append(wdelayerEvents.NewWhiteHackGroupAddress, whiteHackGroupAddress)
464
465		case logWDelayerNewHermezGovernanceDAOAddress:
466			var governanceDAOAddress WDelayerEventNewHermezGovernanceDAOAddress
467			err := c.contractAbi.Unpack(&governanceDAOAddress, "NewHermezGovernanceDAOAddress", vLog.Data)
468			if err != nil {
469				return nil, nil, err
470			}
471			wdelayerEvents.NewHermezGovernanceDAOAddress = append(wdelayerEvents.NewHermezGovernanceDAOAddress, governanceDAOAddress)
472		}
473	}
474	return &wdelayerEvents, blockHash, nil
475}