Fix exit table, set delayed_withdrawn in exits
- In exit table, `instant_withdrawn`, `delayed_withdraw_request`, and
`delayed_withdrawn` were referencing batch_num. But these actions happen
outside a batch, so they should reference a block_num.
- Process delayed withdrawns:
- In Synchronizer, first match a Rollup delayed withdrawn request, with the
WDelayer deposit (via TxHash), and store the owner and token associated
with the delayed withdrawn.
- In HistoryDB: store the owner and token of a delayed withdrawal request
in the exit_tree, and set delayed_withdrawn when the withdraw is done in
the WDelayer.
- Update dependency of sqlx to master
- Last release of sqlx is from 2018 October, and it doesn't support
`NamedQuery` with a slice of structs, which is used in this commit.
4 years ago Fix exit table, set delayed_withdrawn in exits
- In exit table, `instant_withdrawn`, `delayed_withdraw_request`, and
`delayed_withdrawn` were referencing batch_num. But these actions happen
outside a batch, so they should reference a block_num.
- Process delayed withdrawns:
- In Synchronizer, first match a Rollup delayed withdrawn request, with the
WDelayer deposit (via TxHash), and store the owner and token associated
with the delayed withdrawn.
- In HistoryDB: store the owner and token of a delayed withdrawal request
in the exit_tree, and set delayed_withdrawn when the withdraw is done in
the WDelayer.
- Update dependency of sqlx to master
- Last release of sqlx is from 2018 October, and it doesn't support
`NamedQuery` with a slice of structs, which is used in this commit.
4 years ago |
|
package eth
import ( "context" "fmt" "math/big" "strconv" "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" Hermez "github.com/hermeznetwork/hermez-node/eth/contracts/hermez" HEZ "github.com/hermeznetwork/hermez-node/eth/contracts/tokenHEZ" "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/tracerr" "github.com/iden3/go-iden3-crypto/babyjub" )
// QueueStruct is the queue of L1Txs for a batch
type QueueStruct struct { L1TxQueue []common.L1Tx TotalL1TxFee *big.Int }
// NewQueueStruct creates a new clear QueueStruct.
func NewQueueStruct() *QueueStruct { return &QueueStruct{ L1TxQueue: make([]common.L1Tx, 0), TotalL1TxFee: big.NewInt(0), } }
// RollupState represents the state of the Rollup in the Smart Contract
type RollupState struct { StateRoot *big.Int ExitRoots []*big.Int // ExitNullifierMap map[[256 / 8]byte]bool
ExitNullifierMap map[int64]map[int64]bool // batchNum -> idx -> bool
TokenList []ethCommon.Address TokenMap map[ethCommon.Address]bool MapL1TxQueue map[int64]*QueueStruct LastL1L2Batch int64 CurrentToForgeL1TxsNum int64 LastToForgeL1TxsNum int64 CurrentIdx int64 }
// RollupEventInitialize is the InitializeHermezEvent event of the
// Smart Contract
type RollupEventInitialize struct { ForgeL1L2BatchTimeout uint8 FeeAddToken *big.Int WithdrawalDelay uint64 }
// RollupEventL1UserTx is an event of the Rollup Smart Contract
type RollupEventL1UserTx struct { // ToForgeL1TxsNum int64 // QueueIndex *big.Int
// Position int // TransactionIndex *big.Int
L1UserTx common.L1Tx }
// RollupEventL1UserTxAux is an event of the Rollup Smart Contract
type rollupEventL1UserTxAux struct { ToForgeL1TxsNum uint64 // QueueIndex *big.Int
Position uint8 // TransactionIndex *big.Int
L1UserTx []byte }
// RollupEventAddToken is an event of the Rollup Smart Contract
type RollupEventAddToken struct { TokenAddress ethCommon.Address TokenID uint32 }
// RollupEventForgeBatch is an event of the Rollup Smart Contract
type RollupEventForgeBatch struct { BatchNum int64 // Sender ethCommon.Address
EthTxHash ethCommon.Hash L1UserTxsLen uint16 }
// RollupEventUpdateForgeL1L2BatchTimeout is an event of the Rollup Smart Contract
type RollupEventUpdateForgeL1L2BatchTimeout struct { NewForgeL1L2BatchTimeout int64 }
// RollupEventUpdateFeeAddToken is an event of the Rollup Smart Contract
type RollupEventUpdateFeeAddToken struct { NewFeeAddToken *big.Int }
// RollupEventWithdraw is an event of the Rollup Smart Contract
type RollupEventWithdraw struct { Idx uint64 NumExitRoot uint64 InstantWithdraw bool TxHash ethCommon.Hash // Hash of the transaction that generated this event
}
type rollupEventUpdateBucketWithdrawAux struct { NumBucket uint8 BlockStamp *big.Int Withdrawals *big.Int }
// RollupEventUpdateBucketWithdraw is an event of the Rollup Smart Contract
type RollupEventUpdateBucketWithdraw struct { NumBucket int BlockStamp int64 // blockNum
Withdrawals *big.Int }
// RollupEventUpdateWithdrawalDelay is an event of the Rollup Smart Contract
type RollupEventUpdateWithdrawalDelay struct { NewWithdrawalDelay uint64 }
// RollupUpdateBucketsParameters are the bucket parameters used in an update
type RollupUpdateBucketsParameters struct { CeilUSD *big.Int Withdrawals *big.Int BlockWithdrawalRate *big.Int MaxWithdrawals *big.Int }
type rollupEventUpdateBucketsParametersAux struct { ArrayBuckets [common.RollupConstNumBuckets][4]*big.Int }
// RollupEventUpdateBucketsParameters is an event of the Rollup Smart Contract
type RollupEventUpdateBucketsParameters struct { // ArrayBuckets [common.RollupConstNumBuckets][4]*big.Int
ArrayBuckets [common.RollupConstNumBuckets]RollupUpdateBucketsParameters SafeMode bool }
// RollupEventUpdateTokenExchange is an event of the Rollup Smart Contract
type RollupEventUpdateTokenExchange struct { AddressArray []ethCommon.Address ValueArray []uint64 }
// RollupEventSafeMode is an event of the Rollup Smart Contract
type RollupEventSafeMode struct { }
// RollupEvents is the list of events in a block of the Rollup Smart Contract
type RollupEvents struct { L1UserTx []RollupEventL1UserTx AddToken []RollupEventAddToken ForgeBatch []RollupEventForgeBatch UpdateForgeL1L2BatchTimeout []RollupEventUpdateForgeL1L2BatchTimeout UpdateFeeAddToken []RollupEventUpdateFeeAddToken Withdraw []RollupEventWithdraw UpdateWithdrawalDelay []RollupEventUpdateWithdrawalDelay UpdateBucketWithdraw []RollupEventUpdateBucketWithdraw UpdateBucketsParameters []RollupEventUpdateBucketsParameters UpdateTokenExchange []RollupEventUpdateTokenExchange SafeMode []RollupEventSafeMode }
// NewRollupEvents creates an empty RollupEvents with the slices initialized.
func NewRollupEvents() RollupEvents { return RollupEvents{ L1UserTx: make([]RollupEventL1UserTx, 0), AddToken: make([]RollupEventAddToken, 0), ForgeBatch: make([]RollupEventForgeBatch, 0), UpdateForgeL1L2BatchTimeout: make([]RollupEventUpdateForgeL1L2BatchTimeout, 0), UpdateFeeAddToken: make([]RollupEventUpdateFeeAddToken, 0), Withdraw: make([]RollupEventWithdraw, 0), } }
// RollupForgeBatchArgs are the arguments to the ForgeBatch function in the Rollup Smart Contract
type RollupForgeBatchArgs struct { NewLastIdx int64 NewStRoot *big.Int NewExitRoot *big.Int L1UserTxs []common.L1Tx L1CoordinatorTxs []common.L1Tx L1CoordinatorTxsAuths [][]byte // Authorization for accountCreations for each L1CoordinatorTx
L2TxsData []common.L2Tx FeeIdxCoordinator []common.Idx // Circuit selector
VerifierIdx uint8 L1Batch bool ProofA [2]*big.Int ProofB [2][2]*big.Int ProofC [2]*big.Int }
// RollupForgeBatchArgsAux are the arguments to the ForgeBatch function in the Rollup Smart Contract
type rollupForgeBatchArgsAux struct { NewLastIdx *big.Int NewStRoot *big.Int NewExitRoot *big.Int EncodedL1CoordinatorTx []byte L1L2TxsData []byte FeeIdxCoordinator []byte // Circuit selector
VerifierIdx uint8 L1Batch bool ProofA [2]*big.Int ProofB [2][2]*big.Int ProofC [2]*big.Int }
// RollupInterface is the inteface to to Rollup Smart Contract
type RollupInterface interface { //
// Smart Contract Methods
//
// Public Functions
RollupForgeBatch(*RollupForgeBatchArgs) (*types.Transaction, error) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (*types.Transaction, error)
RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error) RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error)
RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error) RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error)
// Governance Public Functions
RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (*types.Transaction, error) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (*types.Transaction, error)
// Viewers
RollupRegisterTokensCount() (*big.Int, error) RollupLastForgedBatch() (int64, error)
//
// Smart Contract Status
//
RollupConstants() (*common.RollupConstants, error) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) RollupForgeBatchArgs(ethCommon.Hash, uint16) (*RollupForgeBatchArgs, *ethCommon.Address, error) }
//
// Implementation
//
// RollupClient is the implementation of the interface to the Rollup Smart Contract in ethereum.
type RollupClient struct { client *EthereumClient chainID *big.Int address ethCommon.Address tokenHEZCfg TokenConfig hermez *Hermez.Hermez tokenHEZ *HEZ.HEZ contractAbi abi.ABI opts *bind.CallOpts }
// NewRollupClient creates a new RollupClient
func NewRollupClient(client *EthereumClient, address ethCommon.Address, tokenHEZCfg TokenConfig) (*RollupClient, error) { contractAbi, err := abi.JSON(strings.NewReader(string(Hermez.HermezABI))) if err != nil { return nil, tracerr.Wrap(err) } hermez, err := Hermez.NewHermez(address, client.Client()) if err != nil { return nil, tracerr.Wrap(err) } tokenHEZ, err := HEZ.NewHEZ(tokenHEZCfg.Address, client.Client()) if err != nil { return nil, tracerr.Wrap(err) } chainID, err := client.client.ChainID(context.Background()) if err != nil { return nil, tracerr.Wrap(err) } return &RollupClient{ client: client, chainID: chainID, address: address, tokenHEZCfg: tokenHEZCfg, hermez: hermez, tokenHEZ: tokenHEZ, contractAbi: contractAbi, opts: newCallOpts(), }, nil }
// RollupForgeBatch is the interface to call the smart contract function
func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (tx *types.Transaction, err error) { if tx, err = c.client.CallAuth( 1000000, //nolint:gomnd
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { rollupConst, err := c.RollupConstants() if err != nil { return nil, tracerr.Wrap(err) } nLevels := rollupConst.Verifiers[args.VerifierIdx].NLevels lenBytes := nLevels / 8 //nolint:gomnd
newLastIdx := big.NewInt(int64(args.NewLastIdx)) // L1CoordinatorBytes
var l1CoordinatorBytes []byte for i := 0; i < len(args.L1CoordinatorTxs); i++ { l1 := args.L1CoordinatorTxs[i] bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i]) if err != nil { return nil, tracerr.Wrap(err) } l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...) } // L1L2TxData
var l1l2TxData []byte for i := 0; i < len(args.L1UserTxs); i++ { l1User := args.L1UserTxs[i] bytesl1User, err := l1User.BytesDataAvailability(uint32(nLevels)) if err != nil { return nil, tracerr.Wrap(err) } l1l2TxData = append(l1l2TxData, bytesl1User[:]...) } for i := 0; i < len(args.L1CoordinatorTxs); i++ { l1Coord := args.L1CoordinatorTxs[i] bytesl1Coord, err := l1Coord.BytesDataAvailability(uint32(nLevels)) if err != nil { return nil, tracerr.Wrap(err) } l1l2TxData = append(l1l2TxData, bytesl1Coord[:]...) } for i := 0; i < len(args.L2TxsData); i++ { l2 := args.L2TxsData[i] bytesl2, err := l2.BytesDataAvailability(uint32(nLevels)) if err != nil { return nil, tracerr.Wrap(err) } l1l2TxData = append(l1l2TxData, bytesl2[:]...) } // FeeIdxCoordinator
var feeIdxCoordinator []byte if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator { return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v", common.RollupConstMaxFeeIdxCoordinator)) } for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ { feeIdx := common.Idx(0) if i < len(args.FeeIdxCoordinator) { feeIdx = args.FeeIdxCoordinator[i] } bytesFeeIdx, err := feeIdx.Bytes() if err != nil { return nil, tracerr.Wrap(err) } feeIdxCoordinator = append(feeIdxCoordinator, bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...) } return c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, l1CoordinatorBytes, l1l2TxData, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, args.ProofA, args.ProofB, args.ProofC) }, ); err != nil { return nil, tracerr.Wrap(fmt.Errorf("Failed forge batch: %w", err)) } return tx, nil }
// RollupAddToken is the interface to call the smart contract function.
// `feeAddToken` is the amount of HEZ tokens that will be paid to add the
// token. `feeAddToken` must match the public value of the smart contract.
func (c *RollupClient) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (tx *types.Transaction, err error) { if tx, err = c.client.CallAuth( 0, func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { owner := c.client.account.Address spender := c.address nonce, err := c.tokenHEZ.Nonces(c.opts, owner) if err != nil { return nil, tracerr.Wrap(err) } tokenName := c.tokenHEZCfg.Name tokenAddr := c.tokenHEZCfg.Address digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, feeAddToken, nonce, deadline, tokenName) signature, _ := c.client.ks.SignHash(*c.client.account, digest) permit := createPermit(owner, spender, feeAddToken, deadline, digest, signature)
return c.hermez.AddToken(auth, tokenAddress, permit) }, ); err != nil { return nil, tracerr.Wrap(fmt.Errorf("Failed add Token %w", err)) } return tx, nil }
// RollupWithdrawMerkleProof is the interface to call the smart contract function
func (c *RollupClient) RollupWithdrawMerkleProof(fromBJJ *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) { if tx, err = c.client.CallAuth( 0, func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { pkCompL := fromBJJ.Compress() pkCompB := common.SwapEndianness(pkCompL[:]) babyPubKey := new(big.Int).SetBytes(pkCompB) numExitRootB := uint32(numExitRoot) idxBig := big.NewInt(idx) return c.hermez.WithdrawMerkleProof(auth, tokenID, amount, babyPubKey, numExitRootB, siblings, idxBig, instantWithdraw) }, ); err != nil { return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawMerkleProof: %w", err)) } return tx, nil }
// RollupWithdrawCircuit is the interface to call the smart contract function
func (c *RollupClient) RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error) { log.Error("TODO") return nil, tracerr.Wrap(errTODO) }
// RollupL1UserTxERC20ETH is the interface to call the smart contract function
func (c *RollupClient) RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (tx *types.Transaction, err error) { if tx, err = c.client.CallAuth( 0, func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { var babyPubKey *big.Int if fromBJJ != nil { pkCompL := fromBJJ.Compress() pkCompB := common.SwapEndianness(pkCompL[:]) babyPubKey = new(big.Int).SetBytes(pkCompB) } else { babyPubKey = big.NewInt(0) } fromIdxBig := big.NewInt(fromIdx) toIdxBig := big.NewInt(toIdx) depositAmountF, err := common.NewFloat16(depositAmount) if err != nil { return nil, tracerr.Wrap(err) } amountF, err := common.NewFloat16(amount) if err != nil { return nil, tracerr.Wrap(err) } if tokenID == 0 { auth.Value = depositAmount } var permit []byte return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(depositAmountF), uint16(amountF), tokenID, toIdxBig, permit) }, ); err != nil { return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20/ETH: %w", err)) } return tx, nil }
// RollupL1UserTxERC20Permit is the interface to call the smart contract function
func (c *RollupClient) RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error) { if tx, err = c.client.CallAuth( 0, func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { var babyPubKey *big.Int if fromBJJ != nil { pkCompL := fromBJJ.Compress() pkCompB := common.SwapEndianness(pkCompL[:]) babyPubKey = new(big.Int).SetBytes(pkCompB) } else { babyPubKey = big.NewInt(0) } fromIdxBig := big.NewInt(fromIdx) toIdxBig := big.NewInt(toIdx) depositAmountF, err := common.NewFloat16(depositAmount) if err != nil { return nil, tracerr.Wrap(err) } amountF, err := common.NewFloat16(amount) if err != nil { return nil, tracerr.Wrap(err) } if tokenID == 0 { auth.Value = depositAmount } owner := c.client.account.Address spender := c.address nonce, err := c.tokenHEZ.Nonces(c.opts, owner) if err != nil { return nil, tracerr.Wrap(err) } tokenName := c.tokenHEZCfg.Name tokenAddr := c.tokenHEZCfg.Address digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, amount, nonce, deadline, tokenName) signature, _ := c.client.ks.SignHash(*c.client.account, digest) permit := createPermit(owner, spender, amount, deadline, digest, signature) return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(depositAmountF), uint16(amountF), tokenID, toIdxBig, permit) }, ); err != nil { return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20Permit: %w", err)) } return tx, nil }
// RollupRegisterTokensCount is the interface to call the smart contract function
func (c *RollupClient) RollupRegisterTokensCount() (registerTokensCount *big.Int, err error) { if err := c.client.Call(func(ec *ethclient.Client) error { registerTokensCount, err = c.hermez.RegisterTokensCount(c.opts) return tracerr.Wrap(err) }); err != nil { return nil, tracerr.Wrap(err) } return registerTokensCount, nil }
// RollupLastForgedBatch is the interface to call the smart contract function
func (c *RollupClient) RollupLastForgedBatch() (lastForgedBatch int64, err error) { if err := c.client.Call(func(ec *ethclient.Client) error { _lastForgedBatch, err := c.hermez.LastForgedBatch(c.opts) lastForgedBatch = int64(_lastForgedBatch) return tracerr.Wrap(err) }); err != nil { return 0, tracerr.Wrap(err) } return lastForgedBatch, nil }
// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
func (c *RollupClient) RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (tx *types.Transaction, err error) { if tx, err = c.client.CallAuth( 0, func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { return c.hermez.UpdateForgeL1L2BatchTimeout(auth, uint8(newForgeL1L2BatchTimeout)) }, ); err != nil { return nil, tracerr.Wrap(fmt.Errorf("Failed update ForgeL1L2BatchTimeout: %w", err)) } return tx, nil }
// RollupUpdateFeeAddToken is the interface to call the smart contract function
func (c *RollupClient) RollupUpdateFeeAddToken(newFeeAddToken *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.hermez.UpdateFeeAddToken(auth, newFeeAddToken) }, ); err != nil { return nil, tracerr.Wrap(fmt.Errorf("Failed update FeeAddToken: %w", err)) } return tx, nil }
// RollupUpdateBucketsParameters is the interface to call the smart contract function
func (c *RollupClient) RollupUpdateBucketsParameters( arrayBuckets [common.RollupConstNumBuckets]RollupUpdateBucketsParameters, ) (tx *types.Transaction, err error) { params := [common.RollupConstNumBuckets][4]*big.Int{} for i, bucket := range arrayBuckets { params[i][0] = bucket.CeilUSD params[i][1] = bucket.Withdrawals params[i][2] = bucket.BlockWithdrawalRate params[i][3] = bucket.MaxWithdrawals } if tx, err = c.client.CallAuth( 12500000, //nolint:gomnd
func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { return c.hermez.UpdateBucketsParameters(auth, params) }, ); err != nil { return nil, tracerr.Wrap(fmt.Errorf("Failed update Buckets Parameters: %w", err)) } return tx, nil }
// RollupUpdateTokenExchange is the interface to call the smart contract function
func (c *RollupClient) RollupUpdateTokenExchange(addressArray []ethCommon.Address, valueArray []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.hermez.UpdateTokenExchange(auth, addressArray, valueArray) }, ); err != nil { return nil, tracerr.Wrap(fmt.Errorf("Failed update Token Exchange: %w", err)) } return tx, nil }
// RollupUpdateWithdrawalDelay is the interface to call the smart contract function
func (c *RollupClient) RollupUpdateWithdrawalDelay(newWithdrawalDelay int64) (tx *types.Transaction, err error) { if tx, err = c.client.CallAuth( 0, func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { return c.hermez.UpdateWithdrawalDelay(auth, uint64(newWithdrawalDelay)) }, ); err != nil { return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawalDelay: %w", err)) } return tx, nil }
// RollupSafeMode is the interface to call the smart contract function
func (c *RollupClient) RollupSafeMode() (tx *types.Transaction, err error) { if tx, err = c.client.CallAuth( 0, func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { return c.hermez.SafeMode(auth) }, ); err != nil { return nil, tracerr.Wrap(fmt.Errorf("Failed update Safe Mode: %w", err)) } return tx, nil }
// RollupInstantWithdrawalViewer is the interface to call the smart contract function
func (c *RollupClient) RollupInstantWithdrawalViewer(tokenAddress ethCommon.Address, amount *big.Int) (instantAllowed bool, err error) { if err := c.client.Call(func(ec *ethclient.Client) error { instantAllowed, err = c.hermez.InstantWithdrawalViewer(c.opts, tokenAddress, amount) return tracerr.Wrap(err) }); err != nil { return false, tracerr.Wrap(err) } return instantAllowed, nil }
// RollupConstants returns the Constants of the Rollup Smart Contract
func (c *RollupClient) RollupConstants() (rollupConstants *common.RollupConstants, err error) { rollupConstants = new(common.RollupConstants) if err := c.client.Call(func(ec *ethclient.Client) error { absoluteMaxL1L2BatchTimeout, err := c.hermez.ABSOLUTEMAXL1L2BATCHTIMEOUT(c.opts) if err != nil { return tracerr.Wrap(err) } rollupConstants.AbsoluteMaxL1L2BatchTimeout = int64(absoluteMaxL1L2BatchTimeout) rollupConstants.TokenHEZ, err = c.hermez.TokenHEZ(c.opts) if err != nil { return tracerr.Wrap(err) } for i := int64(0); i < int64(common.LenVerifiers); i++ { var newRollupVerifier common.RollupVerifierStruct rollupVerifier, err := c.hermez.RollupVerifiers(c.opts, big.NewInt(i)) if err != nil { return tracerr.Wrap(err) } newRollupVerifier.MaxTx = rollupVerifier.MaxTx.Int64() newRollupVerifier.NLevels = rollupVerifier.NLevels.Int64() rollupConstants.Verifiers = append(rollupConstants.Verifiers, newRollupVerifier) } rollupConstants.HermezAuctionContract, err = c.hermez.HermezAuctionContract(c.opts) if err != nil { return tracerr.Wrap(err) } rollupConstants.HermezGovernanceAddress, err = c.hermez.HermezGovernanceAddress(c.opts) if err != nil { return tracerr.Wrap(err) } rollupConstants.WithdrawDelayerContract, err = c.hermez.WithdrawDelayerContract(c.opts) return tracerr.Wrap(err) }); err != nil { return nil, tracerr.Wrap(err) } return rollupConstants, nil }
var ( logHermezL1UserTxEvent = crypto.Keccak256Hash([]byte("L1UserTxEvent(uint32,uint8,bytes)")) logHermezAddToken = crypto.Keccak256Hash([]byte("AddToken(address,uint32)")) logHermezForgeBatch = crypto.Keccak256Hash([]byte("ForgeBatch(uint32,uint16)")) logHermezUpdateForgeL1L2BatchTimeout = crypto.Keccak256Hash([]byte("UpdateForgeL1L2BatchTimeout(uint8)")) logHermezUpdateFeeAddToken = crypto.Keccak256Hash([]byte("UpdateFeeAddToken(uint256)")) logHermezWithdrawEvent = crypto.Keccak256Hash([]byte("WithdrawEvent(uint48,uint32,bool)")) logHermezUpdateBucketWithdraw = crypto.Keccak256Hash([]byte("UpdateBucketWithdraw(uint8,uint256,uint256)")) logHermezUpdateWithdrawalDelay = crypto.Keccak256Hash([]byte("UpdateWithdrawalDelay(uint64)")) logHermezUpdateBucketsParameters = crypto.Keccak256Hash([]byte("UpdateBucketsParameters(uint256[4][" + strconv.Itoa(common.RollupConstNumBuckets) + "])")) logHermezUpdateTokenExchange = crypto.Keccak256Hash([]byte("UpdateTokenExchange(address[],uint64[])")) logHermezSafeMode = crypto.Keccak256Hash([]byte("SafeMode()")) logHermezInitialize = crypto.Keccak256Hash([]byte("InitializeHermezEvent(uint8,uint256,uint64)")) )
// RollupEventInit returns the initialize event with its corresponding block number
func (c *RollupClient) RollupEventInit() (*RollupEventInitialize, int64, error) { query := ethereum.FilterQuery{ Addresses: []ethCommon.Address{ c.address, }, Topics: [][]ethCommon.Hash{{logHermezInitialize}}, } logs, err := c.client.client.FilterLogs(context.Background(), query) if err != nil { return nil, 0, tracerr.Wrap(err) } if len(logs) != 1 { return nil, 0, fmt.Errorf("no event of type InitializeHermezEvent found") } vLog := logs[0] if vLog.Topics[0] != logHermezInitialize { return nil, 0, fmt.Errorf("event is not InitializeHermezEvent") }
var rollupInit RollupEventInitialize if err := c.contractAbi.UnpackIntoInterface(&rollupInit, "InitializeHermezEvent", vLog.Data); err != nil { return nil, 0, tracerr.Wrap(err) } return &rollupInit, int64(vLog.BlockNumber), err }
// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) { var rollupEvents RollupEvents 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, tracerr.Wrap(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, tracerr.Wrap(ErrBlockHashMismatchEvent) } switch vLog.Topics[0] { case logHermezL1UserTxEvent: var L1UserTxAux rollupEventL1UserTxAux var L1UserTx RollupEventL1UserTx err := c.contractAbi.UnpackIntoInterface(&L1UserTxAux, "L1UserTxEvent", vLog.Data) if err != nil { return nil, nil, tracerr.Wrap(err) } L1Tx, err := common.L1UserTxFromBytes(L1UserTxAux.L1UserTx) if err != nil { return nil, nil, tracerr.Wrap(err) } toForgeL1TxsNum := new(big.Int).SetBytes(vLog.Topics[1][:]).Int64() L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum L1Tx.Position = int(new(big.Int).SetBytes(vLog.Topics[2][:]).Int64()) L1Tx.UserOrigin = true L1UserTx.L1UserTx = *L1Tx rollupEvents.L1UserTx = append(rollupEvents.L1UserTx, L1UserTx) case logHermezAddToken: var addToken RollupEventAddToken err := c.contractAbi.UnpackIntoInterface(&addToken, "AddToken", vLog.Data) if err != nil { return nil, nil, tracerr.Wrap(err) } addToken.TokenAddress = ethCommon.BytesToAddress(vLog.Topics[1].Bytes()) rollupEvents.AddToken = append(rollupEvents.AddToken, addToken) case logHermezForgeBatch: var forgeBatch RollupEventForgeBatch err := c.contractAbi.UnpackIntoInterface(&forgeBatch, "ForgeBatch", vLog.Data) if err != nil { return nil, nil, tracerr.Wrap(err) } forgeBatch.BatchNum = new(big.Int).SetBytes(vLog.Topics[1][:]).Int64() forgeBatch.EthTxHash = vLog.TxHash // forgeBatch.Sender = vLog.Address
rollupEvents.ForgeBatch = append(rollupEvents.ForgeBatch, forgeBatch) case logHermezUpdateForgeL1L2BatchTimeout: var updateForgeL1L2BatchTimeout struct { NewForgeL1L2BatchTimeout uint8 } err := c.contractAbi.UnpackIntoInterface(&updateForgeL1L2BatchTimeout, "UpdateForgeL1L2BatchTimeout", vLog.Data) if err != nil { return nil, nil, tracerr.Wrap(err) } rollupEvents.UpdateForgeL1L2BatchTimeout = append(rollupEvents.UpdateForgeL1L2BatchTimeout, RollupEventUpdateForgeL1L2BatchTimeout{ NewForgeL1L2BatchTimeout: int64(updateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout), }) case logHermezUpdateFeeAddToken: var updateFeeAddToken RollupEventUpdateFeeAddToken err := c.contractAbi.UnpackIntoInterface(&updateFeeAddToken, "UpdateFeeAddToken", vLog.Data) if err != nil { return nil, nil, tracerr.Wrap(err) } rollupEvents.UpdateFeeAddToken = append(rollupEvents.UpdateFeeAddToken, updateFeeAddToken) case logHermezWithdrawEvent: var withdraw RollupEventWithdraw withdraw.Idx = new(big.Int).SetBytes(vLog.Topics[1][:]).Uint64() withdraw.NumExitRoot = new(big.Int).SetBytes(vLog.Topics[2][:]).Uint64() instantWithdraw := new(big.Int).SetBytes(vLog.Topics[3][:]).Uint64() if instantWithdraw == 1 { withdraw.InstantWithdraw = true } withdraw.TxHash = vLog.TxHash rollupEvents.Withdraw = append(rollupEvents.Withdraw, withdraw) case logHermezUpdateBucketWithdraw: var updateBucketWithdrawAux rollupEventUpdateBucketWithdrawAux var updateBucketWithdraw RollupEventUpdateBucketWithdraw err := c.contractAbi.UnpackIntoInterface(&updateBucketWithdrawAux, "UpdateBucketWithdraw", vLog.Data) if err != nil { return nil, nil, tracerr.Wrap(err) } updateBucketWithdraw.Withdrawals = updateBucketWithdrawAux.Withdrawals updateBucketWithdraw.NumBucket = int(new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()) updateBucketWithdraw.BlockStamp = new(big.Int).SetBytes(vLog.Topics[2][:]).Int64() rollupEvents.UpdateBucketWithdraw = append(rollupEvents.UpdateBucketWithdraw, updateBucketWithdraw)
case logHermezUpdateWithdrawalDelay: var withdrawalDelay RollupEventUpdateWithdrawalDelay err := c.contractAbi.UnpackIntoInterface(&withdrawalDelay, "UpdateWithdrawalDelay", vLog.Data) if err != nil { return nil, nil, tracerr.Wrap(err) } rollupEvents.UpdateWithdrawalDelay = append(rollupEvents.UpdateWithdrawalDelay, withdrawalDelay) case logHermezUpdateBucketsParameters: var bucketsParametersAux rollupEventUpdateBucketsParametersAux var bucketsParameters RollupEventUpdateBucketsParameters err := c.contractAbi.UnpackIntoInterface(&bucketsParametersAux, "UpdateBucketsParameters", vLog.Data) if err != nil { return nil, nil, tracerr.Wrap(err) } for i, bucket := range bucketsParametersAux.ArrayBuckets { bucketsParameters.ArrayBuckets[i].CeilUSD = bucket[0] bucketsParameters.ArrayBuckets[i].Withdrawals = bucket[1] bucketsParameters.ArrayBuckets[i].BlockWithdrawalRate = bucket[2] bucketsParameters.ArrayBuckets[i].MaxWithdrawals = bucket[3] } rollupEvents.UpdateBucketsParameters = append(rollupEvents.UpdateBucketsParameters, bucketsParameters) case logHermezUpdateTokenExchange: var tokensExchange RollupEventUpdateTokenExchange err := c.contractAbi.UnpackIntoInterface(&tokensExchange, "UpdateTokenExchange", vLog.Data) if err != nil { return nil, nil, tracerr.Wrap(err) } rollupEvents.UpdateTokenExchange = append(rollupEvents.UpdateTokenExchange, tokensExchange) case logHermezSafeMode: var safeMode RollupEventSafeMode rollupEvents.SafeMode = append(rollupEvents.SafeMode, safeMode) // Also add an UpdateBucketsParameter with
// SafeMode=true to keep the order between `safeMode`
// and `UpdateBucketsParameters`
bucketsParameters := RollupEventUpdateBucketsParameters{ SafeMode: true, } for i := range bucketsParameters.ArrayBuckets { bucketsParameters.ArrayBuckets[i].CeilUSD = big.NewInt(0) bucketsParameters.ArrayBuckets[i].Withdrawals = big.NewInt(0) bucketsParameters.ArrayBuckets[i].BlockWithdrawalRate = big.NewInt(0) bucketsParameters.ArrayBuckets[i].MaxWithdrawals = big.NewInt(0) } rollupEvents.UpdateBucketsParameters = append(rollupEvents.UpdateBucketsParameters, bucketsParameters) } } return &rollupEvents, blockHash, nil }
// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the
// Rollup Smart Contract in the given transaction, and the sender address.
func (c *RollupClient) RollupForgeBatchArgs(ethTxHash ethCommon.Hash, l1UserTxsLen uint16) (*RollupForgeBatchArgs, *ethCommon.Address, error) { tx, _, err := c.client.client.TransactionByHash(context.Background(), ethTxHash) if err != nil { return nil, nil, tracerr.Wrap(err) } txData := tx.Data()
method, err := c.contractAbi.MethodById(txData[:4]) if err != nil { return nil, nil, tracerr.Wrap(err) } receipt, err := c.client.client.TransactionReceipt(context.Background(), ethTxHash) if err != nil { return nil, nil, tracerr.Wrap(err) } sender, err := c.client.client.TransactionSender(context.Background(), tx, receipt.Logs[0].BlockHash, receipt.Logs[0].Index) if err != nil { return nil, nil, tracerr.Wrap(err) } var aux rollupForgeBatchArgsAux if values, err := method.Inputs.Unpack(txData[4:]); err != nil { return nil, nil, tracerr.Wrap(err) } else if err := method.Inputs.Copy(&aux, values); err != nil { return nil, nil, tracerr.Wrap(err) } rollupForgeBatchArgs := RollupForgeBatchArgs{ L1Batch: aux.L1Batch, NewExitRoot: aux.NewExitRoot, NewLastIdx: aux.NewLastIdx.Int64(), NewStRoot: aux.NewStRoot, ProofA: aux.ProofA, ProofB: aux.ProofB, ProofC: aux.ProofC, VerifierIdx: aux.VerifierIdx, L1CoordinatorTxs: []common.L1Tx{}, L1CoordinatorTxsAuths: [][]byte{}, L2TxsData: []common.L2Tx{}, FeeIdxCoordinator: []common.Idx{}, } rollupConsts, err := c.RollupConstants() if err != nil { return nil, nil, tracerr.Wrap(err) } nLevels := rollupConsts.Verifiers[rollupForgeBatchArgs.VerifierIdx].NLevels lenL1L2TxsBytes := int((nLevels/8)*2 + 2 + 1) numBytesL1TxUser := int(l1UserTxsLen) * lenL1L2TxsBytes numTxsL1Coord := len(aux.EncodedL1CoordinatorTx) / common.L1CoordinatorTxBytesLen numBytesL1TxCoord := numTxsL1Coord * lenL1L2TxsBytes numBeginL2Tx := numBytesL1TxCoord + numBytesL1TxUser l1UserTxsData := []byte{} if l1UserTxsLen > 0 { l1UserTxsData = aux.L1L2TxsData[:numBytesL1TxUser] } for i := 0; i < int(l1UserTxsLen); i++ { l1Tx, err := common.L1TxFromDataAvailability(l1UserTxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], uint32(nLevels)) if err != nil { return nil, nil, tracerr.Wrap(err) } rollupForgeBatchArgs.L1UserTxs = append(rollupForgeBatchArgs.L1UserTxs, *l1Tx) } l2TxsData := []byte{} if numBeginL2Tx < len(aux.L1L2TxsData) { l2TxsData = aux.L1L2TxsData[numBeginL2Tx:] } numTxsL2 := len(l2TxsData) / lenL1L2TxsBytes for i := 0; i < numTxsL2; i++ { l2Tx, err := common.L2TxFromBytesDataAvailability(l2TxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], int(nLevels)) if err != nil { return nil, nil, tracerr.Wrap(err) } rollupForgeBatchArgs.L2TxsData = append(rollupForgeBatchArgs.L2TxsData, *l2Tx) } for i := 0; i < numTxsL1Coord; i++ { bytesL1Coordinator := aux.EncodedL1CoordinatorTx[i*common.L1CoordinatorTxBytesLen : (i+1)*common.L1CoordinatorTxBytesLen] var signature []byte v := bytesL1Coordinator[0] s := bytesL1Coordinator[1:33] r := bytesL1Coordinator[33:65] signature = append(signature, r[:]...) signature = append(signature, s[:]...) signature = append(signature, v) l1Tx, err := common.L1CoordinatorTxFromBytes(bytesL1Coordinator, c.chainID, c.address) if err != nil { return nil, nil, tracerr.Wrap(err) } rollupForgeBatchArgs.L1CoordinatorTxs = append(rollupForgeBatchArgs.L1CoordinatorTxs, *l1Tx) rollupForgeBatchArgs.L1CoordinatorTxsAuths = append(rollupForgeBatchArgs.L1CoordinatorTxsAuths, signature) } lenFeeIdxCoordinatorBytes := int(nLevels / 8) //nolint:gomnd
numFeeIdxCoordinator := len(aux.FeeIdxCoordinator) / lenFeeIdxCoordinatorBytes for i := 0; i < numFeeIdxCoordinator; i++ { var paddedFeeIdx [6]byte // TODO: This check is not necessary: the first case will always work. Test it before removing the if.
if lenFeeIdxCoordinatorBytes < common.IdxBytesLen { copy(paddedFeeIdx[6-lenFeeIdxCoordinatorBytes:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes]) } else { copy(paddedFeeIdx[:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes]) } feeIdxCoordinator, err := common.IdxFromBytes(paddedFeeIdx[:]) if err != nil { return nil, nil, tracerr.Wrap(err) } if feeIdxCoordinator != common.Idx(0) { rollupForgeBatchArgs.FeeIdxCoordinator = append(rollupForgeBatchArgs.FeeIdxCoordinator, feeIdxCoordinator) } } return &rollupForgeBatchArgs, &sender, nil }
|