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	"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}