You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

474 lines
18 KiB

package eth
import (
"context"
"fmt"
"math/big"
"strings"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/hermeznetwork/hermez-node/common"
WithdrawalDelayer "github.com/hermeznetwork/hermez-node/eth/contracts/withdrawdelayer"
"github.com/hermeznetwork/hermez-node/log"
)
// DepositState is the state of Deposit
type DepositState struct {
Amount *big.Int
DepositTimestamp uint64
}
// WDelayerEventDeposit is an event of the WithdrawalDelayer Smart Contract
type WDelayerEventDeposit struct {
Owner ethCommon.Address
Token ethCommon.Address
Amount *big.Int
DepositTimestamp uint64
}
// WDelayerEventWithdraw is an event of the WithdrawalDelayer Smart Contract
type WDelayerEventWithdraw struct {
Owner ethCommon.Address
Token ethCommon.Address
Amount *big.Int
}
// WDelayerEventEmergencyModeEnabled an event of the WithdrawalDelayer Smart Contract
type WDelayerEventEmergencyModeEnabled struct {
}
// WDelayerEventNewWithdrawalDelay an event of the WithdrawalDelayer Smart Contract
type WDelayerEventNewWithdrawalDelay struct {
WithdrawalDelay uint64
}
// WDelayerEventEscapeHatchWithdrawal an event of the WithdrawalDelayer Smart Contract
type WDelayerEventEscapeHatchWithdrawal struct {
Who ethCommon.Address
To ethCommon.Address
Token ethCommon.Address
Amount *big.Int
}
// WDelayerEventNewHermezKeeperAddress an event of the WithdrawalDelayer Smart Contract
type WDelayerEventNewHermezKeeperAddress struct {
NewHermezKeeperAddress ethCommon.Address
}
// WDelayerEventNewWhiteHackGroupAddress an event of the WithdrawalDelayer Smart Contract
type WDelayerEventNewWhiteHackGroupAddress struct {
NewWhiteHackGroupAddress ethCommon.Address
}
// WDelayerEventNewHermezGovernanceDAOAddress an event of the WithdrawalDelayer Smart Contract
type WDelayerEventNewHermezGovernanceDAOAddress struct {
NewHermezGovernanceDAOAddress ethCommon.Address
}
// WDelayerEvents is the lis of events in a block of the WithdrawalDelayer Smart Contract
type WDelayerEvents struct {
Deposit []WDelayerEventDeposit
Withdraw []WDelayerEventWithdraw
EmergencyModeEnabled []WDelayerEventEmergencyModeEnabled
NewWithdrawalDelay []WDelayerEventNewWithdrawalDelay
EscapeHatchWithdrawal []WDelayerEventEscapeHatchWithdrawal
NewHermezKeeperAddress []WDelayerEventNewHermezKeeperAddress
NewWhiteHackGroupAddress []WDelayerEventNewWhiteHackGroupAddress
NewHermezGovernanceDAOAddress []WDelayerEventNewHermezGovernanceDAOAddress
}
// NewWDelayerEvents creates an empty WDelayerEvents with the slices initialized.
func NewWDelayerEvents() WDelayerEvents {
return WDelayerEvents{
Deposit: make([]WDelayerEventDeposit, 0),
Withdraw: make([]WDelayerEventWithdraw, 0),
EmergencyModeEnabled: make([]WDelayerEventEmergencyModeEnabled, 0),
NewWithdrawalDelay: make([]WDelayerEventNewWithdrawalDelay, 0),
EscapeHatchWithdrawal: make([]WDelayerEventEscapeHatchWithdrawal, 0),
NewHermezKeeperAddress: make([]WDelayerEventNewHermezKeeperAddress, 0),
NewWhiteHackGroupAddress: make([]WDelayerEventNewWhiteHackGroupAddress, 0),
NewHermezGovernanceDAOAddress: make([]WDelayerEventNewHermezGovernanceDAOAddress, 0),
}
}
// WDelayerInterface is the inteface to WithdrawalDelayer Smart Contract
type WDelayerInterface interface {
//
// Smart Contract Methods
//
WDelayerGetHermezGovernanceDAOAddress() (*ethCommon.Address, error)
WDelayerSetHermezGovernanceDAOAddress(newAddress ethCommon.Address) (*types.Transaction, error)
WDelayerGetHermezKeeperAddress() (*ethCommon.Address, error)
WDelayerSetHermezKeeperAddress(newAddress ethCommon.Address) (*types.Transaction, error)
WDelayerGetWhiteHackGroupAddress() (*ethCommon.Address, error)
WDelayerSetWhiteHackGroupAddress(newAddress ethCommon.Address) (*types.Transaction, error)
WDelayerIsEmergencyMode() (bool, error)
WDelayerGetWithdrawalDelay() (*big.Int, error)
WDelayerGetEmergencyModeStartingTime() (*big.Int, error)
WDelayerEnableEmergencyMode() (*types.Transaction, error)
WDelayerChangeWithdrawalDelay(newWithdrawalDelay uint64) (*types.Transaction, error)
WDelayerDepositInfo(owner, token ethCommon.Address) (*big.Int, uint64)
WDelayerDeposit(onwer, token ethCommon.Address, amount *big.Int) (*types.Transaction, error)
WDelayerWithdrawal(owner, token ethCommon.Address) (*types.Transaction, error)
WDelayerEscapeHatchWithdrawal(to, token ethCommon.Address, amount *big.Int) (*types.Transaction, error)
WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents, *ethCommon.Hash, error)
WDelayerConstants() (*common.WDelayerConstants, error)
}
//
// Implementation
//
// WDelayerClient is the implementation of the interface to the WithdrawDelayer Smart Contract in ethereum.
type WDelayerClient struct {
client *EthereumClient
address ethCommon.Address
wdelayer *WithdrawalDelayer.WithdrawalDelayer
contractAbi abi.ABI
}
// NewWDelayerClient creates a new WDelayerClient
func NewWDelayerClient(client *EthereumClient, address ethCommon.Address) (*WDelayerClient, error) {
contractAbi, err := abi.JSON(strings.NewReader(string(WithdrawalDelayer.WithdrawalDelayerABI)))
if err != nil {
return nil, err
}
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(address, client.Client())
if err != nil {
return nil, err
}
return &WDelayerClient{
client: client,
address: address,
wdelayer: wdelayer,
contractAbi: contractAbi,
}, nil
}
// WDelayerGetHermezGovernanceDAOAddress is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerGetHermezGovernanceDAOAddress() (hermezGovernanceDAOAddress *ethCommon.Address, err error) {
var _hermezGovernanceDAOAddress ethCommon.Address
if err := c.client.Call(func(ec *ethclient.Client) error {
_hermezGovernanceDAOAddress, err = c.wdelayer.GetHermezGovernanceDAOAddress(nil)
return err
}); err != nil {
return nil, err
}
return &_hermezGovernanceDAOAddress, nil
}
// WDelayerSetHermezGovernanceDAOAddress is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerSetHermezGovernanceDAOAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
if tx, err = c.client.CallAuth(
0,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
return c.wdelayer.SetHermezGovernanceDAOAddress(auth, newAddress)
},
); err != nil {
return nil, fmt.Errorf("Failed setting hermezGovernanceDAOAddress: %w", err)
}
return tx, nil
}
// WDelayerGetHermezKeeperAddress is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerGetHermezKeeperAddress() (hermezKeeperAddress *ethCommon.Address, err error) {
var _hermezKeeperAddress ethCommon.Address
if err := c.client.Call(func(ec *ethclient.Client) error {
_hermezKeeperAddress, err = c.wdelayer.GetHermezKeeperAddress(nil)
return err
}); err != nil {
return nil, err
}
return &_hermezKeeperAddress, nil
}
// WDelayerSetHermezKeeperAddress is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerSetHermezKeeperAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
if tx, err = c.client.CallAuth(
0,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
return c.wdelayer.SetHermezKeeperAddress(auth, newAddress)
},
); err != nil {
return nil, fmt.Errorf("Failed setting hermezKeeperAddress: %w", err)
}
return tx, nil
}
// WDelayerGetWhiteHackGroupAddress is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerGetWhiteHackGroupAddress() (whiteHackGroupAddress *ethCommon.Address, err error) {
var _whiteHackGroupAddress ethCommon.Address
if err := c.client.Call(func(ec *ethclient.Client) error {
_whiteHackGroupAddress, err = c.wdelayer.GetWhiteHackGroupAddress(nil)
return err
}); err != nil {
return nil, err
}
return &_whiteHackGroupAddress, nil
}
// WDelayerSetWhiteHackGroupAddress is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerSetWhiteHackGroupAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
if tx, err = c.client.CallAuth(
0,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
return c.wdelayer.SetWhiteHackGroupAddress(auth, newAddress)
},
); err != nil {
return nil, fmt.Errorf("Failed setting whiteHackGroupAddress: %w", err)
}
return tx, nil
}
// WDelayerIsEmergencyMode is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerIsEmergencyMode() (ermergencyMode bool, err error) {
if err := c.client.Call(func(ec *ethclient.Client) error {
ermergencyMode, err = c.wdelayer.IsEmergencyMode(nil)
return err
}); err != nil {
return false, err
}
return ermergencyMode, nil
}
// WDelayerGetWithdrawalDelay is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerGetWithdrawalDelay() (withdrawalDelay *big.Int, err error) {
if err := c.client.Call(func(ec *ethclient.Client) error {
withdrawalDelay, err = c.wdelayer.GetWithdrawalDelay(nil)
return err
}); err != nil {
return nil, err
}
return withdrawalDelay, nil
}
// WDelayerGetEmergencyModeStartingTime is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerGetEmergencyModeStartingTime() (emergencyModeStartingTime *big.Int, err error) {
if err := c.client.Call(func(ec *ethclient.Client) error {
emergencyModeStartingTime, err = c.wdelayer.GetEmergencyModeStartingTime(nil)
return err
}); err != nil {
return nil, err
}
return emergencyModeStartingTime, nil
}
// WDelayerEnableEmergencyMode is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerEnableEmergencyMode() (tx *types.Transaction, err error) {
if tx, err = c.client.CallAuth(
0,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
return c.wdelayer.EnableEmergencyMode(auth)
},
); err != nil {
return nil, fmt.Errorf("Failed setting enable emergency mode: %w", err)
}
return tx, nil
}
// WDelayerChangeWithdrawalDelay is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerChangeWithdrawalDelay(newWithdrawalDelay uint64) (tx *types.Transaction, err error) {
if tx, err = c.client.CallAuth(
0,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
return c.wdelayer.ChangeWithdrawalDelay(auth, newWithdrawalDelay)
},
); err != nil {
return nil, fmt.Errorf("Failed setting withdrawal delay: %w", err)
}
return tx, nil
}
// WDelayerDepositInfo is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerDepositInfo(owner, token ethCommon.Address) (depositInfo DepositState, err error) {
if err := c.client.Call(func(ec *ethclient.Client) error {
amount, depositTimestamp, err := c.wdelayer.DepositInfo(nil, owner, token)
depositInfo.Amount = amount
depositInfo.DepositTimestamp = depositTimestamp
return err
}); err != nil {
return depositInfo, err
}
return depositInfo, nil
}
// WDelayerDeposit is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerDeposit(owner, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
if tx, err = c.client.CallAuth(
0,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
return c.wdelayer.Deposit(auth, owner, token, amount)
},
); err != nil {
return nil, fmt.Errorf("Failed deposit: %w", err)
}
return tx, nil
}
// WDelayerWithdrawal is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerWithdrawal(owner, token ethCommon.Address) (tx *types.Transaction, err error) {
if tx, err = c.client.CallAuth(
0,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
return c.wdelayer.Withdrawal(auth, owner, token)
},
); err != nil {
return nil, fmt.Errorf("Failed withdrawal: %w", err)
}
return tx, nil
}
// WDelayerEscapeHatchWithdrawal is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerEscapeHatchWithdrawal(to, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
if tx, err = c.client.CallAuth(
0,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
return c.wdelayer.EscapeHatchWithdrawal(auth, to, token, amount)
},
); err != nil {
return nil, fmt.Errorf("Failed escapeHatchWithdrawal: %w", err)
}
return tx, nil
}
// WDelayerConstants returns the Constants of the WDelayer Smart Contract
func (c *WDelayerClient) WDelayerConstants() (constants common.WDelayerConstants, err error) {
if err := c.client.Call(func(ec *ethclient.Client) error {
constants.MaxWithdrawalDelay, err = c.wdelayer.MAXWITHDRAWALDELAY(nil)
if err != nil {
return err
}
constants.MaxEmergencyModeTime, err = c.wdelayer.MAXEMERGENCYMODETIME(nil)
if err != nil {
return err
}
constants.HermezRollup, err = c.wdelayer.HermezRollupAddress(nil)
if err != nil {
return err
}
return err
}); err != nil {
return constants, err
}
return constants, nil
}
var (
logWDelayerDeposit = crypto.Keccak256Hash([]byte("Deposit(address,address,uint192,uint64)"))
logWDelayerWithdraw = crypto.Keccak256Hash([]byte("Withdraw(address,address,uint192)"))
logWDelayerEmergencyModeEnabled = crypto.Keccak256Hash([]byte("EmergencyModeEnabled()"))
logWDelayerNewWithdrawalDelay = crypto.Keccak256Hash([]byte("NewWithdrawalDelay(uint64)"))
logWDelayerEscapeHatchWithdrawal = crypto.Keccak256Hash([]byte("EscapeHatchWithdrawal(address,address,address,uint256)"))
logWDelayerNewHermezKeeperAddress = crypto.Keccak256Hash([]byte("NewHermezKeeperAddress(address)"))
logWDelayerNewWhiteHackGroupAddress = crypto.Keccak256Hash([]byte("NewWhiteHackGroupAddress(address)"))
logWDelayerNewHermezGovernanceDAOAddress = crypto.Keccak256Hash([]byte("NewHermezGovernanceDAOAddress(address)"))
)
// WDelayerEventsByBlock returns the events in a block that happened in the
// WDelayer Smart Contract and the blockHash where the eents happened. If
// there are no events in that block, blockHash is nil.
func (c *WDelayerClient) WDelayerEventsByBlock(blockNum int64) (*WDelayerEvents, *ethCommon.Hash, error) {
var wdelayerEvents WDelayerEvents
var blockHash ethCommon.Hash
query := ethereum.FilterQuery{
FromBlock: big.NewInt(blockNum),
ToBlock: big.NewInt(blockNum),
Addresses: []ethCommon.Address{
c.address,
},
BlockHash: nil,
Topics: [][]ethCommon.Hash{},
}
logs, err := c.client.client.FilterLogs(context.Background(), query)
if err != nil {
return nil, nil, err
}
if len(logs) > 0 {
blockHash = logs[0].BlockHash
}
for _, vLog := range logs {
if vLog.BlockHash != blockHash {
log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String())
return nil, nil, ErrBlockHashMismatchEvent
}
switch vLog.Topics[0] {
case logWDelayerDeposit:
var deposit WDelayerEventDeposit
err := c.contractAbi.Unpack(&deposit, "Deposit", vLog.Data)
if err != nil {
return nil, nil, err
}
deposit.Owner = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
deposit.Token = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
wdelayerEvents.Deposit = append(wdelayerEvents.Deposit, deposit)
case logWDelayerWithdraw:
var withdraw WDelayerEventWithdraw
err := c.contractAbi.Unpack(&withdraw, "Withdraw", vLog.Data)
if err != nil {
return nil, nil, err
}
withdraw.Token = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
withdraw.Owner = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
wdelayerEvents.Withdraw = append(wdelayerEvents.Withdraw, withdraw)
case logWDelayerEmergencyModeEnabled:
var emergencyModeEnabled WDelayerEventEmergencyModeEnabled
wdelayerEvents.EmergencyModeEnabled = append(wdelayerEvents.EmergencyModeEnabled, emergencyModeEnabled)
case logWDelayerNewWithdrawalDelay:
var withdrawalDelay WDelayerEventNewWithdrawalDelay
err := c.contractAbi.Unpack(&withdrawalDelay, "NewWithdrawalDelay", vLog.Data)
if err != nil {
return nil, nil, err
}
wdelayerEvents.NewWithdrawalDelay = append(wdelayerEvents.NewWithdrawalDelay, withdrawalDelay)
case logWDelayerEscapeHatchWithdrawal:
var escapeHatchWithdrawal WDelayerEventEscapeHatchWithdrawal
err := c.contractAbi.Unpack(&escapeHatchWithdrawal, "EscapeHatchWithdrawal", vLog.Data)
if err != nil {
return nil, nil, err
}
escapeHatchWithdrawal.Who = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
escapeHatchWithdrawal.To = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
escapeHatchWithdrawal.Token = ethCommon.BytesToAddress(vLog.Topics[3].Bytes())
wdelayerEvents.EscapeHatchWithdrawal = append(wdelayerEvents.EscapeHatchWithdrawal, escapeHatchWithdrawal)
case logWDelayerNewHermezKeeperAddress:
var keeperAddress WDelayerEventNewHermezKeeperAddress
err := c.contractAbi.Unpack(&keeperAddress, "NewHermezKeeperAddress", vLog.Data)
if err != nil {
return nil, nil, err
}
wdelayerEvents.NewHermezKeeperAddress = append(wdelayerEvents.NewHermezKeeperAddress, keeperAddress)
case logWDelayerNewWhiteHackGroupAddress:
var whiteHackGroupAddress WDelayerEventNewWhiteHackGroupAddress
err := c.contractAbi.Unpack(&whiteHackGroupAddress, "NewWhiteHackGroupAddress", vLog.Data)
if err != nil {
return nil, nil, err
}
wdelayerEvents.NewWhiteHackGroupAddress = append(wdelayerEvents.NewWhiteHackGroupAddress, whiteHackGroupAddress)
case logWDelayerNewHermezGovernanceDAOAddress:
var governanceDAOAddress WDelayerEventNewHermezGovernanceDAOAddress
err := c.contractAbi.Unpack(&governanceDAOAddress, "NewHermezGovernanceDAOAddress", vLog.Data)
if err != nil {
return nil, nil, err
}
wdelayerEvents.NewHermezGovernanceDAOAddress = append(wdelayerEvents.NewHermezGovernanceDAOAddress, governanceDAOAddress)
}
}
return &wdelayerEvents, &blockHash, nil
}