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.
 
 
 

525 lines
19 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"
WithdrawalDelayer "github.com/hermeznetwork/hermez-node/eth/contracts/withdrawdelayer"
)
// WDelayerConstants are the constants of the Rollup Smart Contract
type WDelayerConstants struct {
// Max Withdrawal Delay
MaxWithdrawalDelay uint64
// Max Emergency mode time
MaxEmergencyModeTime uint64
// HermezRollup smartcontract address
HermezRollup ethCommon.Address
}
// 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
}
// 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 { //nolint:structcheck
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) (*types.Transaction, error)
}
//
// Implementation
//
// WDelayerClient is the implementation of the interface to the WithdrawDelayer Smart Contract in ethereum.
type WDelayerClient struct {
client *EthereumClient
address ethCommon.Address
gasLimit uint64
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
}
return &WDelayerClient{
client: client,
address: address,
gasLimit: 1000000, //nolint:gomnd
contractAbi: contractAbi,
}, nil
}
// WDelayerGetHermezGovernanceDAOAddress is the interface to call the smart contract function
func (c *WDelayerClient) WDelayerGetHermezGovernanceDAOAddress() (*ethCommon.Address, error) {
var hermezGovernanceDAOAddress ethCommon.Address
if err := c.client.Call(func(ec *ethclient.Client) error {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return err
}
hermezGovernanceDAOAddress, err = 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) (*types.Transaction, error) {
var tx *types.Transaction
var err error
if tx, err = c.client.CallAuth(
c.gasLimit,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return nil, err
}
return 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() (*ethCommon.Address, error) {
var hermezKeeperAddress ethCommon.Address
if err := c.client.Call(func(ec *ethclient.Client) error {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return err
}
hermezKeeperAddress, err = 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) (*types.Transaction, error) {
var tx *types.Transaction
var err error
if tx, err = c.client.CallAuth(
c.gasLimit,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return nil, err
}
return 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() (*ethCommon.Address, error) {
var whiteHackGroupAddress ethCommon.Address
if err := c.client.Call(func(ec *ethclient.Client) error {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return err
}
whiteHackGroupAddress, err = 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) (*types.Transaction, error) {
var tx *types.Transaction
var err error
if tx, err = c.client.CallAuth(
c.gasLimit,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return nil, err
}
return 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() (bool, error) {
var ermergencyMode bool
if err := c.client.Call(func(ec *ethclient.Client) error {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return err
}
ermergencyMode, err = 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() (*big.Int, error) {
var withdrawalDelay *big.Int
if err := c.client.Call(func(ec *ethclient.Client) error {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return err
}
withdrawalDelay, err = 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() (*big.Int, error) {
var emergencyModeStartingTime *big.Int
if err := c.client.Call(func(ec *ethclient.Client) error {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return err
}
emergencyModeStartingTime, err = 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() (*types.Transaction, error) {
var tx *types.Transaction
var err error
if tx, err = c.client.CallAuth(
c.gasLimit,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return nil, err
}
return 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) (*types.Transaction, error) {
var tx *types.Transaction
var err error
if tx, err = c.client.CallAuth(
c.gasLimit,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return nil, err
}
return 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) (DepositState, error) {
var depositInfo DepositState
if err := c.client.Call(func(ec *ethclient.Client) error {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return err
}
amount, depositTimestamp, err := 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) (*types.Transaction, error) {
var tx *types.Transaction
var err error
if tx, err = c.client.CallAuth(
c.gasLimit,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return nil, err
}
return 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) (*types.Transaction, error) {
var tx *types.Transaction
var err error
if tx, err = c.client.CallAuth(
c.gasLimit,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return nil, err
}
return 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) (*types.Transaction, error) {
var tx *types.Transaction
var err error
if tx, err = c.client.CallAuth(
c.gasLimit,
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
wdelayer, err := WithdrawalDelayer.NewWithdrawalDelayer(c.address, ec)
if err != nil {
return nil, err
}
return wdelayer.EscapeHatchWithdrawal(auth, to, token)
},
); err != nil {
return nil, fmt.Errorf("Failed escapeHatchWithdrawal: %w", err)
}
return tx, nil
}
var (
logDeposit = crypto.Keccak256Hash([]byte("Deposit(address,address,uint192,uint64)"))
logWithdraw = crypto.Keccak256Hash([]byte("Withdraw(address,address,uint192)"))
logEmergencyModeEnabled = crypto.Keccak256Hash([]byte("EmergencyModeEnabled()"))
logNewWithdrawalDelay = crypto.Keccak256Hash([]byte("NewWithdrawalDelay(uint64)"))
logEscapeHatchWithdrawal = crypto.Keccak256Hash([]byte("EscapeHatchWithdrawal(address,address,address)"))
logNewHermezKeeperAddress = crypto.Keccak256Hash([]byte("NewHermezKeeperAddress(address)"))
logNewWhiteHackGroupAddress = crypto.Keccak256Hash([]byte("NewWhiteHackGroupAddress(address)"))
logNewHermezGovernanceDAOAddress = crypto.Keccak256Hash([]byte("NewHermezGovernanceDAOAddress(address)"))
)
// WDelayerEventsByBlock returns the events in a block that happened in the WDelayer Smart Contract
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 {
fmt.Println(err)
}
if len(logs) > 0 {
blockHash = logs[0].BlockHash
}
for _, vLog := range logs {
if vLog.BlockHash != blockHash {
return nil, nil, err
}
switch vLog.Topics[0] {
case logDeposit:
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 logWithdraw:
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 logEmergencyModeEnabled:
var emergencyModeEnabled WDelayerEventEmergencyModeEnabled
wdelayerEvents.EmergencyModeEnabled = append(wdelayerEvents.EmergencyModeEnabled, emergencyModeEnabled)
case logNewWithdrawalDelay:
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 logEscapeHatchWithdrawal:
var escapeHatchWithdrawal WDelayerEventEscapeHatchWithdrawal
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 logNewHermezKeeperAddress:
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 logNewWhiteHackGroupAddress:
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 logNewHermezGovernanceDAOAddress:
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
}