arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/eth/rollup.go
eth/rollup.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	Hermez "github.com/hermeznetwork/hermez-node/eth/contracts/hermez"
 18	HEZ "github.com/hermeznetwork/hermez-node/eth/contracts/tokenHEZ"
 19	"github.com/hermeznetwork/hermez-node/log"
 20	"github.com/hermeznetwork/tracerr"
 21	"github.com/iden3/go-iden3-crypto/babyjub"
 22)
 23
 24// QueueStruct is the queue of L1Txs for a batch
 25type QueueStruct struct {
 26	L1TxQueue    []common.L1Tx
 27	TotalL1TxFee *big.Int
 28}
 29
 30// NewQueueStruct creates a new clear QueueStruct.
 31func NewQueueStruct() *QueueStruct {
 32	return &QueueStruct{
 33		L1TxQueue:    make([]common.L1Tx, 0),
 34		TotalL1TxFee: big.NewInt(0),
 35	}
 36}
 37
 38// RollupState represents the state of the Rollup in the Smart Contract
 39type RollupState struct {
 40	StateRoot *big.Int
 41	ExitRoots []*big.Int
 42	// ExitNullifierMap       map[[256 / 8]byte]bool
 43	ExitNullifierMap       map[int64]map[int64]bool // batchNum -> idx -> bool
 44	TokenList              []ethCommon.Address
 45	TokenMap               map[ethCommon.Address]bool
 46	MapL1TxQueue           map[int64]*QueueStruct
 47	LastL1L2Batch          int64
 48	CurrentToForgeL1TxsNum int64
 49	LastToForgeL1TxsNum    int64
 50	CurrentIdx             int64
 51}
 52
 53// RollupEventL1UserTx is an event of the Rollup Smart Contract
 54type RollupEventL1UserTx struct {
 55	// ToForgeL1TxsNum int64 // QueueIndex       *big.Int
 56	// Position        int   // TransactionIndex *big.Int
 57	L1UserTx common.L1Tx
 58}
 59
 60// RollupEventL1UserTxAux is an event of the Rollup Smart Contract
 61type RollupEventL1UserTxAux struct {
 62	ToForgeL1TxsNum uint64 // QueueIndex       *big.Int
 63	Position        uint8  // TransactionIndex *big.Int
 64	L1UserTx        []byte
 65}
 66
 67// RollupEventAddToken is an event of the Rollup Smart Contract
 68type RollupEventAddToken struct {
 69	TokenAddress ethCommon.Address
 70	TokenID      uint32
 71}
 72
 73// RollupEventForgeBatch is an event of the Rollup Smart Contract
 74type RollupEventForgeBatch struct {
 75	BatchNum int64
 76	// Sender    ethCommon.Address
 77	EthTxHash ethCommon.Hash
 78}
 79
 80// RollupEventUpdateForgeL1L2BatchTimeout is an event of the Rollup Smart Contract
 81type RollupEventUpdateForgeL1L2BatchTimeout struct {
 82	NewForgeL1L2BatchTimeout int64
 83}
 84
 85// RollupEventUpdateFeeAddToken is an event of the Rollup Smart Contract
 86type RollupEventUpdateFeeAddToken struct {
 87	NewFeeAddToken *big.Int
 88}
 89
 90// RollupEventWithdraw is an event of the Rollup Smart Contract
 91type RollupEventWithdraw struct {
 92	Idx             uint64
 93	NumExitRoot     uint64
 94	InstantWithdraw bool
 95	TxHash          ethCommon.Hash // Hash of the transaction that generated this event
 96}
 97
 98// RollupEvents is the list of events in a block of the Rollup Smart Contract
 99type RollupEvents struct {
100	L1UserTx                    []RollupEventL1UserTx
101	AddToken                    []RollupEventAddToken
102	ForgeBatch                  []RollupEventForgeBatch
103	UpdateForgeL1L2BatchTimeout []RollupEventUpdateForgeL1L2BatchTimeout
104	UpdateFeeAddToken           []RollupEventUpdateFeeAddToken
105	Withdraw                    []RollupEventWithdraw
106}
107
108// NewRollupEvents creates an empty RollupEvents with the slices initialized.
109func NewRollupEvents() RollupEvents {
110	return RollupEvents{
111		L1UserTx:                    make([]RollupEventL1UserTx, 0),
112		AddToken:                    make([]RollupEventAddToken, 0),
113		ForgeBatch:                  make([]RollupEventForgeBatch, 0),
114		UpdateForgeL1L2BatchTimeout: make([]RollupEventUpdateForgeL1L2BatchTimeout, 0),
115		UpdateFeeAddToken:           make([]RollupEventUpdateFeeAddToken, 0),
116		Withdraw:                    make([]RollupEventWithdraw, 0),
117	}
118}
119
120// RollupForgeBatchArgs are the arguments to the ForgeBatch function in the Rollup Smart Contract
121type RollupForgeBatchArgs struct {
122	NewLastIdx            int64
123	NewStRoot             *big.Int
124	NewExitRoot           *big.Int
125	L1CoordinatorTxs      []common.L1Tx
126	L1CoordinatorTxsAuths [][]byte // Authorization for accountCreations for each L1CoordinatorTx
127	L2TxsData             []common.L2Tx
128	FeeIdxCoordinator     []common.Idx
129	// Circuit selector
130	VerifierIdx uint8
131	L1Batch     bool
132	ProofA      [2]*big.Int
133	ProofB      [2][2]*big.Int
134	ProofC      [2]*big.Int
135}
136
137// RollupForgeBatchArgsAux are the arguments to the ForgeBatch function in the Rollup Smart Contract
138type RollupForgeBatchArgsAux struct {
139	NewLastIdx             *big.Int
140	NewStRoot              *big.Int
141	NewExitRoot            *big.Int
142	EncodedL1CoordinatorTx []byte
143	L2TxsData              []byte
144	FeeIdxCoordinator      []byte
145	// Circuit selector
146	VerifierIdx uint8
147	L1Batch     bool
148	ProofA      [2]*big.Int
149	ProofB      [2][2]*big.Int
150	ProofC      [2]*big.Int
151}
152
153// RollupInterface is the inteface to to Rollup Smart Contract
154type RollupInterface interface {
155	//
156	// Smart Contract Methods
157	//
158
159	// Public Functions
160
161	RollupForgeBatch(*RollupForgeBatchArgs) (*types.Transaction, error)
162	RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (*types.Transaction, error)
163
164	RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error)
165	RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error)
166
167	RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error)
168	RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error)
169
170	// Governance Public Functions
171	RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (*types.Transaction, error)
172	RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (*types.Transaction, error)
173
174	// Viewers
175	RollupRegisterTokensCount() (*big.Int, error)
176	RollupLastForgedBatch() (int64, error)
177
178	//
179	// Smart Contract Status
180	//
181
182	RollupConstants() (*common.RollupConstants, error)
183	RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error)
184	RollupForgeBatchArgs(ethCommon.Hash) (*RollupForgeBatchArgs, *ethCommon.Address, error)
185}
186
187//
188// Implementation
189//
190
191// RollupClient is the implementation of the interface to the Rollup Smart Contract in ethereum.
192type RollupClient struct {
193	client      *EthereumClient
194	chainID     *big.Int
195	address     ethCommon.Address
196	tokenHEZCfg TokenConfig
197	hermez      *Hermez.Hermez
198	tokenHEZ    *HEZ.HEZ
199	contractAbi abi.ABI
200}
201
202// NewRollupClient creates a new RollupClient
203func NewRollupClient(client *EthereumClient, address ethCommon.Address, tokenHEZCfg TokenConfig) (*RollupClient, error) {
204	contractAbi, err := abi.JSON(strings.NewReader(string(Hermez.HermezABI)))
205	if err != nil {
206		return nil, tracerr.Wrap(err)
207	}
208	hermez, err := Hermez.NewHermez(address, client.Client())
209	if err != nil {
210		return nil, tracerr.Wrap(err)
211	}
212	tokenHEZ, err := HEZ.NewHEZ(tokenHEZCfg.Address, client.Client())
213	if err != nil {
214		return nil, tracerr.Wrap(err)
215	}
216	chainID, err := client.client.ChainID(context.Background())
217	if err != nil {
218		return nil, tracerr.Wrap(err)
219	}
220	return &RollupClient{
221		client:      client,
222		chainID:     chainID,
223		address:     address,
224		tokenHEZCfg: tokenHEZCfg,
225		hermez:      hermez,
226		tokenHEZ:    tokenHEZ,
227		contractAbi: contractAbi,
228	}, nil
229}
230
231// RollupForgeBatch is the interface to call the smart contract function
232func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (tx *types.Transaction, err error) {
233	if tx, err = c.client.CallAuth(
234		1000000, //nolint:gomnd
235		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
236			rollupConst, err := c.RollupConstants()
237			if err != nil {
238				return nil, tracerr.Wrap(err)
239			}
240			nLevels := rollupConst.Verifiers[args.VerifierIdx].NLevels
241			lenBytes := nLevels / 8 //nolint:gomnd
242			newLastIdx := big.NewInt(int64(args.NewLastIdx))
243			var l1CoordinatorBytes []byte
244			for i := 0; i < len(args.L1CoordinatorTxs); i++ {
245				l1 := args.L1CoordinatorTxs[i]
246				bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i])
247				if err != nil {
248					return nil, tracerr.Wrap(err)
249				}
250				l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...)
251			}
252			var l2DataBytes []byte
253			for i := 0; i < len(args.L2TxsData); i++ {
254				l2 := args.L2TxsData[i]
255				bytesl2, err := l2.BytesDataAvailability(uint32(nLevels))
256				if err != nil {
257					return nil, tracerr.Wrap(err)
258				}
259				l2DataBytes = append(l2DataBytes, bytesl2[:]...)
260			}
261			var feeIdxCoordinator []byte
262			if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator {
263				return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v",
264					common.RollupConstMaxFeeIdxCoordinator))
265			}
266			for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ {
267				feeIdx := common.Idx(0)
268				if i < len(args.FeeIdxCoordinator) {
269					feeIdx = args.FeeIdxCoordinator[i]
270				}
271				bytesFeeIdx, err := feeIdx.Bytes()
272				if err != nil {
273					return nil, tracerr.Wrap(err)
274				}
275				feeIdxCoordinator = append(feeIdxCoordinator, bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...)
276			}
277			return c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, l1CoordinatorBytes, l2DataBytes, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, args.ProofA, args.ProofB, args.ProofC)
278		},
279	); err != nil {
280		return nil, tracerr.Wrap(fmt.Errorf("Failed forge batch: %w", err))
281	}
282	return tx, nil
283}
284
285// RollupAddToken is the interface to call the smart contract function.
286// `feeAddToken` is the amount of HEZ tokens that will be paid to add the
287// token.  `feeAddToken` must match the public value of the smart contract.
288func (c *RollupClient) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (tx *types.Transaction, err error) {
289	if tx, err = c.client.CallAuth(
290		0,
291		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
292			owner := c.client.account.Address
293			spender := c.address
294			nonce, err := c.tokenHEZ.Nonces(nil, owner)
295			if err != nil {
296				return nil, tracerr.Wrap(err)
297			}
298			tokenName := c.tokenHEZCfg.Name
299			tokenAddr := c.tokenHEZCfg.Address
300			digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, feeAddToken, nonce, deadline, tokenName)
301			signature, _ := c.client.ks.SignHash(*c.client.account, digest)
302			permit := createPermit(owner, spender, feeAddToken, deadline, digest, signature)
303
304			return c.hermez.AddToken(auth, tokenAddress, permit)
305		},
306	); err != nil {
307		return nil, tracerr.Wrap(fmt.Errorf("Failed add Token %w", err))
308	}
309	return tx, nil
310}
311
312// RollupWithdrawMerkleProof is the interface to call the smart contract function
313func (c *RollupClient) RollupWithdrawMerkleProof(fromBJJ *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (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			pkCompL := fromBJJ.Compress()
318			pkCompB := common.SwapEndianness(pkCompL[:])
319			babyPubKey := new(big.Int).SetBytes(pkCompB)
320			numExitRootB := big.NewInt(numExitRoot)
321			idxBig := big.NewInt(idx)
322			return c.hermez.WithdrawMerkleProof(auth, tokenID, amount, babyPubKey, numExitRootB, siblings, idxBig, instantWithdraw)
323		},
324	); err != nil {
325		return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawMerkleProof: %w", err))
326	}
327	return tx, nil
328}
329
330// RollupWithdrawCircuit is the interface to call the smart contract function
331func (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) {
332	log.Error("TODO")
333	return nil, tracerr.Wrap(errTODO)
334}
335
336// RollupL1UserTxERC20ETH is the interface to call the smart contract function
337func (c *RollupClient) RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (tx *types.Transaction, err error) {
338	if tx, err = c.client.CallAuth(
339		0,
340		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
341			pkCompL := fromBJJ.Compress()
342			pkCompB := common.SwapEndianness(pkCompL[:])
343			babyPubKey := new(big.Int).SetBytes(pkCompB)
344			fromIdxBig := big.NewInt(fromIdx)
345			toIdxBig := big.NewInt(toIdx)
346			loadAmountF, err := common.NewFloat16(loadAmount)
347			if err != nil {
348				return nil, tracerr.Wrap(err)
349			}
350			amountF, err := common.NewFloat16(amount)
351			if err != nil {
352				return nil, tracerr.Wrap(err)
353			}
354			if tokenID == 0 {
355				auth.Value = loadAmount
356			}
357			var permit []byte
358			return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(loadAmountF),
359				uint16(amountF), tokenID, toIdxBig, permit)
360		},
361	); err != nil {
362		return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20/ETH: %w", err))
363	}
364	return tx, nil
365}
366
367// RollupL1UserTxERC20Permit is the interface to call the smart contract function
368func (c *RollupClient) RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error) {
369	if tx, err = c.client.CallAuth(
370		0,
371		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
372			pkCompL := fromBJJ.Compress()
373			pkCompB := common.SwapEndianness(pkCompL[:])
374			babyPubKey := new(big.Int).SetBytes(pkCompB)
375			fromIdxBig := big.NewInt(fromIdx)
376			toIdxBig := big.NewInt(toIdx)
377			loadAmountF, err := common.NewFloat16(loadAmount)
378			if err != nil {
379				return nil, tracerr.Wrap(err)
380			}
381			amountF, err := common.NewFloat16(amount)
382			if err != nil {
383				return nil, tracerr.Wrap(err)
384			}
385			if tokenID == 0 {
386				auth.Value = loadAmount
387			}
388			owner := c.client.account.Address
389			spender := c.address
390			nonce, err := c.tokenHEZ.Nonces(nil, owner)
391			if err != nil {
392				return nil, tracerr.Wrap(err)
393			}
394			tokenName := c.tokenHEZCfg.Name
395			tokenAddr := c.tokenHEZCfg.Address
396			digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, amount, nonce, deadline, tokenName)
397			signature, _ := c.client.ks.SignHash(*c.client.account, digest)
398			permit := createPermit(owner, spender, amount, deadline, digest, signature)
399			return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(loadAmountF),
400				uint16(amountF), tokenID, toIdxBig, permit)
401		},
402	); err != nil {
403		return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20Permit: %w", err))
404	}
405	return tx, nil
406}
407
408// RollupRegisterTokensCount is the interface to call the smart contract function
409func (c *RollupClient) RollupRegisterTokensCount() (registerTokensCount *big.Int, err error) {
410	if err := c.client.Call(func(ec *ethclient.Client) error {
411		registerTokensCount, err = c.hermez.RegisterTokensCount(nil)
412		return tracerr.Wrap(err)
413	}); err != nil {
414		return nil, tracerr.Wrap(err)
415	}
416	return registerTokensCount, nil
417}
418
419// RollupLastForgedBatch is the interface to call the smart contract function
420func (c *RollupClient) RollupLastForgedBatch() (lastForgedBatch int64, err error) {
421	if err := c.client.Call(func(ec *ethclient.Client) error {
422		_lastForgedBatch, err := c.hermez.LastForgedBatch(nil)
423		lastForgedBatch = int64(_lastForgedBatch)
424		return tracerr.Wrap(err)
425	}); err != nil {
426		return 0, tracerr.Wrap(err)
427	}
428	return lastForgedBatch, nil
429}
430
431// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
432func (c *RollupClient) RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (tx *types.Transaction, err error) {
433	if tx, err = c.client.CallAuth(
434		0,
435		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
436			return c.hermez.UpdateForgeL1L2BatchTimeout(auth, uint8(newForgeL1L2BatchTimeout))
437		},
438	); err != nil {
439		return nil, tracerr.Wrap(fmt.Errorf("Failed update ForgeL1L2BatchTimeout: %w", err))
440	}
441	return tx, nil
442}
443
444// RollupUpdateFeeAddToken is the interface to call the smart contract function
445func (c *RollupClient) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
446	if tx, err = c.client.CallAuth(
447		0,
448		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
449			return c.hermez.UpdateFeeAddToken(auth, newFeeAddToken)
450		},
451	); err != nil {
452		return nil, tracerr.Wrap(fmt.Errorf("Failed update FeeAddToken: %w", err))
453	}
454	return tx, nil
455}
456
457// RollupConstants returns the Constants of the Rollup Smart Contract
458func (c *RollupClient) RollupConstants() (rollupConstants *common.RollupConstants, err error) {
459	rollupConstants = new(common.RollupConstants)
460	if err := c.client.Call(func(ec *ethclient.Client) error {
461		absoluteMaxL1L2BatchTimeout, err := c.hermez.ABSOLUTEMAXL1L2BATCHTIMEOUT(nil)
462		if err != nil {
463			return tracerr.Wrap(err)
464		}
465		rollupConstants.AbsoluteMaxL1L2BatchTimeout = int64(absoluteMaxL1L2BatchTimeout)
466		rollupConstants.TokenHEZ, err = c.hermez.TokenHEZ(nil)
467		if err != nil {
468			return tracerr.Wrap(err)
469		}
470		for i := int64(0); i < int64(common.LenVerifiers); i++ {
471			var newRollupVerifier common.RollupVerifierStruct
472			rollupVerifier, err := c.hermez.RollupVerifiers(nil, big.NewInt(i))
473			if err != nil {
474				return tracerr.Wrap(err)
475			}
476			newRollupVerifier.MaxTx = rollupVerifier.MaxTx.Int64()
477			newRollupVerifier.NLevels = rollupVerifier.NLevels.Int64()
478			rollupConstants.Verifiers = append(rollupConstants.Verifiers, newRollupVerifier)
479		}
480		rollupConstants.HermezAuctionContract, err = c.hermez.HermezAuctionContract(nil)
481		if err != nil {
482			return tracerr.Wrap(err)
483		}
484		rollupConstants.HermezGovernanceDAOAddress, err = c.hermez.HermezGovernanceDAOAddress(nil)
485		if err != nil {
486			return tracerr.Wrap(err)
487		}
488		rollupConstants.SafetyAddress, err = c.hermez.SafetyAddress(nil)
489		if err != nil {
490			return tracerr.Wrap(err)
491		}
492		rollupConstants.WithdrawDelayerContract, err = c.hermez.WithdrawDelayerContract(nil)
493		return tracerr.Wrap(err)
494	}); err != nil {
495		return nil, tracerr.Wrap(err)
496	}
497	return rollupConstants, nil
498}
499
500var (
501	logHermezL1UserTxEvent               = crypto.Keccak256Hash([]byte("L1UserTxEvent(uint64,uint8,bytes)"))
502	logHermezAddToken                    = crypto.Keccak256Hash([]byte("AddToken(address,uint32)"))
503	logHermezForgeBatch                  = crypto.Keccak256Hash([]byte("ForgeBatch(uint64)"))
504	logHermezUpdateForgeL1L2BatchTimeout = crypto.Keccak256Hash([]byte("UpdateForgeL1L2BatchTimeout(uint8)"))
505	logHermezUpdateFeeAddToken           = crypto.Keccak256Hash([]byte("UpdateFeeAddToken(uint256)"))
506	logHermezWithdrawEvent               = crypto.Keccak256Hash([]byte("WithdrawEvent(uint48,uint48,bool)"))
507)
508
509// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
510func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) {
511	var rollupEvents RollupEvents
512	var blockHash *ethCommon.Hash
513
514	query := ethereum.FilterQuery{
515		FromBlock: big.NewInt(blockNum),
516		ToBlock:   big.NewInt(blockNum),
517		Addresses: []ethCommon.Address{
518			c.address,
519		},
520		BlockHash: nil,
521		Topics:    [][]ethCommon.Hash{},
522	}
523	logs, err := c.client.client.FilterLogs(context.Background(), query)
524	if err != nil {
525		return nil, nil, tracerr.Wrap(err)
526	}
527	if len(logs) > 0 {
528		blockHash = &logs[0].BlockHash
529	}
530	for _, vLog := range logs {
531		if vLog.BlockHash != *blockHash {
532			log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String())
533			return nil, nil, tracerr.Wrap(ErrBlockHashMismatchEvent)
534		}
535		switch vLog.Topics[0] {
536		case logHermezL1UserTxEvent:
537			var L1UserTxAux RollupEventL1UserTxAux
538			var L1UserTx RollupEventL1UserTx
539			err := c.contractAbi.Unpack(&L1UserTxAux, "L1UserTxEvent", vLog.Data)
540			if err != nil {
541				return nil, nil, tracerr.Wrap(err)
542			}
543			L1Tx, err := common.L1UserTxFromBytes(L1UserTxAux.L1UserTx)
544			if err != nil {
545				return nil, nil, tracerr.Wrap(err)
546			}
547			toForgeL1TxsNum := new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
548			L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
549			L1Tx.Position = int(new(big.Int).SetBytes(vLog.Topics[2][:]).Int64())
550			L1Tx.UserOrigin = true
551			L1UserTx.L1UserTx = *L1Tx
552			rollupEvents.L1UserTx = append(rollupEvents.L1UserTx, L1UserTx)
553		case logHermezAddToken:
554			var addToken RollupEventAddToken
555			err := c.contractAbi.Unpack(&addToken, "AddToken", vLog.Data)
556			if err != nil {
557				return nil, nil, tracerr.Wrap(err)
558			}
559			addToken.TokenAddress = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
560			rollupEvents.AddToken = append(rollupEvents.AddToken, addToken)
561		case logHermezForgeBatch:
562			var forgeBatch RollupEventForgeBatch
563			forgeBatch.BatchNum = new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
564			forgeBatch.EthTxHash = vLog.TxHash
565			// forgeBatch.Sender = vLog.Address
566			rollupEvents.ForgeBatch = append(rollupEvents.ForgeBatch, forgeBatch)
567		case logHermezUpdateForgeL1L2BatchTimeout:
568			var updateForgeL1L2BatchTimeout struct {
569				NewForgeL1L2BatchTimeout uint8
570			}
571			err := c.contractAbi.Unpack(&updateForgeL1L2BatchTimeout, "UpdateForgeL1L2BatchTimeout", vLog.Data)
572			if err != nil {
573				return nil, nil, tracerr.Wrap(err)
574			}
575			rollupEvents.UpdateForgeL1L2BatchTimeout = append(rollupEvents.UpdateForgeL1L2BatchTimeout,
576				RollupEventUpdateForgeL1L2BatchTimeout{
577					NewForgeL1L2BatchTimeout: int64(updateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout),
578				})
579		case logHermezUpdateFeeAddToken:
580			var updateFeeAddToken RollupEventUpdateFeeAddToken
581			err := c.contractAbi.Unpack(&updateFeeAddToken, "UpdateFeeAddToken", vLog.Data)
582			if err != nil {
583				return nil, nil, tracerr.Wrap(err)
584			}
585			rollupEvents.UpdateFeeAddToken = append(rollupEvents.UpdateFeeAddToken, updateFeeAddToken)
586		case logHermezWithdrawEvent:
587			var withdraw RollupEventWithdraw
588			withdraw.Idx = new(big.Int).SetBytes(vLog.Topics[1][:]).Uint64()
589			withdraw.NumExitRoot = new(big.Int).SetBytes(vLog.Topics[2][:]).Uint64()
590			instantWithdraw := new(big.Int).SetBytes(vLog.Topics[3][:]).Uint64()
591			if instantWithdraw == 1 {
592				withdraw.InstantWithdraw = true
593			}
594			withdraw.TxHash = vLog.TxHash
595			rollupEvents.Withdraw = append(rollupEvents.Withdraw, withdraw)
596		}
597	}
598	return &rollupEvents, blockHash, nil
599}
600
601// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the
602// Rollup Smart Contract in the given transaction, and the sender address.
603func (c *RollupClient) RollupForgeBatchArgs(ethTxHash ethCommon.Hash) (*RollupForgeBatchArgs, *ethCommon.Address, error) {
604	tx, _, err := c.client.client.TransactionByHash(context.Background(), ethTxHash)
605	if err != nil {
606		return nil, nil, tracerr.Wrap(err)
607	}
608	txData := tx.Data()
609
610	method, err := c.contractAbi.MethodById(txData[:4])
611	if err != nil {
612		return nil, nil, tracerr.Wrap(err)
613	}
614	receipt, err := c.client.client.TransactionReceipt(context.Background(), ethTxHash)
615	if err != nil {
616		return nil, nil, tracerr.Wrap(err)
617	}
618	sender, err := c.client.client.TransactionSender(context.Background(), tx, receipt.Logs[0].BlockHash, receipt.Logs[0].Index)
619	if err != nil {
620		return nil, nil, tracerr.Wrap(err)
621	}
622	var aux RollupForgeBatchArgsAux
623	if err := method.Inputs.Unpack(&aux, txData[4:]); err != nil {
624		return nil, nil, tracerr.Wrap(err)
625	}
626	rollupForgeBatchArgs := RollupForgeBatchArgs{
627		L1Batch:               aux.L1Batch,
628		NewExitRoot:           aux.NewExitRoot,
629		NewLastIdx:            aux.NewLastIdx.Int64(),
630		NewStRoot:             aux.NewStRoot,
631		ProofA:                aux.ProofA,
632		ProofB:                aux.ProofB,
633		ProofC:                aux.ProofC,
634		VerifierIdx:           aux.VerifierIdx,
635		L1CoordinatorTxs:      []common.L1Tx{},
636		L1CoordinatorTxsAuths: [][]byte{},
637		L2TxsData:             []common.L2Tx{},
638		FeeIdxCoordinator:     []common.Idx{},
639	}
640	numTxsL1 := len(aux.EncodedL1CoordinatorTx) / common.L1CoordinatorTxBytesLen
641	for i := 0; i < numTxsL1; i++ {
642		bytesL1Coordinator := aux.EncodedL1CoordinatorTx[i*common.L1CoordinatorTxBytesLen : (i+1)*common.L1CoordinatorTxBytesLen]
643		var signature []byte
644		v := bytesL1Coordinator[0]
645		s := bytesL1Coordinator[1:33]
646		r := bytesL1Coordinator[33:65]
647		signature = append(signature, r[:]...)
648		signature = append(signature, s[:]...)
649		signature = append(signature, v)
650		l1Tx, err := common.L1CoordinatorTxFromBytes(bytesL1Coordinator, c.chainID, c.address)
651		if err != nil {
652			return nil, nil, tracerr.Wrap(err)
653		}
654		rollupForgeBatchArgs.L1CoordinatorTxs = append(rollupForgeBatchArgs.L1CoordinatorTxs, *l1Tx)
655		rollupForgeBatchArgs.L1CoordinatorTxsAuths = append(rollupForgeBatchArgs.L1CoordinatorTxsAuths, signature)
656	}
657	rollupConsts, err := c.RollupConstants()
658	if err != nil {
659		return nil, nil, tracerr.Wrap(err)
660	}
661	nLevels := rollupConsts.Verifiers[rollupForgeBatchArgs.VerifierIdx].NLevels
662	lenL2TxsBytes := int((nLevels/8)*2 + 2 + 1)
663	numTxsL2 := len(aux.L2TxsData) / lenL2TxsBytes
664	for i := 0; i < numTxsL2; i++ {
665		l2Tx, err := common.L2TxFromBytes(aux.L2TxsData[i*lenL2TxsBytes:(i+1)*lenL2TxsBytes], int(nLevels))
666		if err != nil {
667			return nil, nil, tracerr.Wrap(err)
668		}
669		rollupForgeBatchArgs.L2TxsData = append(rollupForgeBatchArgs.L2TxsData, *l2Tx)
670	}
671	lenFeeIdxCoordinatorBytes := int(nLevels / 8) //nolint:gomnd
672	numFeeIdxCoordinator := len(aux.FeeIdxCoordinator) / lenFeeIdxCoordinatorBytes
673	for i := 0; i < numFeeIdxCoordinator; i++ {
674		var paddedFeeIdx [6]byte
675		// TODO: This check is not necessary: the first case will always work.  Test it before removing the if.
676		if lenFeeIdxCoordinatorBytes < common.IdxBytesLen {
677			copy(paddedFeeIdx[6-lenFeeIdxCoordinatorBytes:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
678		} else {
679			copy(paddedFeeIdx[:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
680		}
681		feeIdxCoordinator, err := common.IdxFromBytes(paddedFeeIdx[:])
682		if err != nil {
683			return nil, nil, tracerr.Wrap(err)
684		}
685		if feeIdxCoordinator != common.Idx(0) {
686			rollupForgeBatchArgs.FeeIdxCoordinator = append(rollupForgeBatchArgs.FeeIdxCoordinator, feeIdxCoordinator)
687		}
688	}
689	return &rollupForgeBatchArgs, &sender, nil
690}