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