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