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