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	"strconv"
  8	"strings"
  9
 10	"github.com/ethereum/go-ethereum"
 11	"github.com/ethereum/go-ethereum/accounts/abi"
 12	"github.com/ethereum/go-ethereum/accounts/abi/bind"
 13	ethCommon "github.com/ethereum/go-ethereum/common"
 14	"github.com/ethereum/go-ethereum/core/types"
 15	"github.com/ethereum/go-ethereum/crypto"
 16	"github.com/ethereum/go-ethereum/ethclient"
 17	"github.com/hermeznetwork/hermez-node/common"
 18	Hermez "github.com/hermeznetwork/hermez-node/eth/contracts/hermez"
 19	HEZ "github.com/hermeznetwork/hermez-node/eth/contracts/tokenHEZ"
 20	"github.com/hermeznetwork/hermez-node/log"
 21	"github.com/hermeznetwork/tracerr"
 22	"github.com/iden3/go-iden3-crypto/babyjub"
 23)
 24
 25// QueueStruct is the queue of L1Txs for a batch
 26type QueueStruct struct {
 27	L1TxQueue    []common.L1Tx
 28	TotalL1TxFee *big.Int
 29}
 30
 31// NewQueueStruct creates a new clear QueueStruct.
 32func NewQueueStruct() *QueueStruct {
 33	return &QueueStruct{
 34		L1TxQueue:    make([]common.L1Tx, 0),
 35		TotalL1TxFee: big.NewInt(0),
 36	}
 37}
 38
 39// RollupState represents the state of the Rollup in the Smart Contract
 40type RollupState struct {
 41	StateRoot *big.Int
 42	ExitRoots []*big.Int
 43	// ExitNullifierMap       map[[256 / 8]byte]bool
 44	ExitNullifierMap       map[int64]map[int64]bool // batchNum -> idx -> bool
 45	TokenList              []ethCommon.Address
 46	TokenMap               map[ethCommon.Address]bool
 47	MapL1TxQueue           map[int64]*QueueStruct
 48	LastL1L2Batch          int64
 49	CurrentToForgeL1TxsNum int64
 50	LastToForgeL1TxsNum    int64
 51	CurrentIdx             int64
 52}
 53
 54// RollupEventInitialize is the InitializeHermezEvent event of the
 55// Smart Contract
 56type RollupEventInitialize struct {
 57	ForgeL1L2BatchTimeout uint8
 58	FeeAddToken           *big.Int
 59	WithdrawalDelay       uint64
 60}
 61
 62// RollupVariables returns the RollupVariables from the initialize event
 63func (ei *RollupEventInitialize) RollupVariables() *common.RollupVariables {
 64	var buckets [common.RollupConstNumBuckets]common.BucketParams
 65	for i := range buckets {
 66		buckets[i] = common.BucketParams{
 67			CeilUSD:             big.NewInt(0),
 68			Withdrawals:         big.NewInt(0),
 69			BlockWithdrawalRate: big.NewInt(0),
 70			MaxWithdrawals:      big.NewInt(0),
 71		}
 72	}
 73	return &common.RollupVariables{
 74		EthBlockNum:           0,
 75		FeeAddToken:           ei.FeeAddToken,
 76		ForgeL1L2BatchTimeout: int64(ei.ForgeL1L2BatchTimeout),
 77		WithdrawalDelay:       ei.WithdrawalDelay,
 78		Buckets:               buckets,
 79		SafeMode:              false,
 80	}
 81}
 82
 83// RollupEventL1UserTx is an event of the Rollup Smart Contract
 84type RollupEventL1UserTx struct {
 85	// ToForgeL1TxsNum int64 // QueueIndex       *big.Int
 86	// Position        int   // TransactionIndex *big.Int
 87	L1UserTx common.L1Tx
 88}
 89
 90// RollupEventL1UserTxAux is an event of the Rollup Smart Contract
 91type rollupEventL1UserTxAux struct {
 92	ToForgeL1TxsNum uint64 // QueueIndex       *big.Int
 93	Position        uint8  // TransactionIndex *big.Int
 94	L1UserTx        []byte
 95}
 96
 97// RollupEventAddToken is an event of the Rollup Smart Contract
 98type RollupEventAddToken struct {
 99	TokenAddress ethCommon.Address
100	TokenID      uint32
101}
102
103// RollupEventForgeBatch is an event of the Rollup Smart Contract
104type RollupEventForgeBatch struct {
105	BatchNum int64
106	// Sender    ethCommon.Address
107	EthTxHash    ethCommon.Hash
108	L1UserTxsLen uint16
109}
110
111// RollupEventUpdateForgeL1L2BatchTimeout is an event of the Rollup Smart Contract
112type RollupEventUpdateForgeL1L2BatchTimeout struct {
113	NewForgeL1L2BatchTimeout int64
114}
115
116// RollupEventUpdateFeeAddToken is an event of the Rollup Smart Contract
117type RollupEventUpdateFeeAddToken struct {
118	NewFeeAddToken *big.Int
119}
120
121// RollupEventWithdraw is an event of the Rollup Smart Contract
122type RollupEventWithdraw struct {
123	Idx             uint64
124	NumExitRoot     uint64
125	InstantWithdraw bool
126	TxHash          ethCommon.Hash // Hash of the transaction that generated this event
127}
128
129type rollupEventUpdateBucketWithdrawAux struct {
130	NumBucket   uint8
131	BlockStamp  *big.Int
132	Withdrawals *big.Int
133}
134
135// RollupEventUpdateBucketWithdraw is an event of the Rollup Smart Contract
136type RollupEventUpdateBucketWithdraw struct {
137	NumBucket   int
138	BlockStamp  int64 // blockNum
139	Withdrawals *big.Int
140}
141
142// RollupEventUpdateWithdrawalDelay is an event of the Rollup Smart Contract
143type RollupEventUpdateWithdrawalDelay struct {
144	NewWithdrawalDelay uint64
145}
146
147// RollupUpdateBucketsParameters are the bucket parameters used in an update
148type RollupUpdateBucketsParameters struct {
149	CeilUSD             *big.Int
150	Withdrawals         *big.Int
151	BlockWithdrawalRate *big.Int
152	MaxWithdrawals      *big.Int
153}
154
155type rollupEventUpdateBucketsParametersAux struct {
156	ArrayBuckets [common.RollupConstNumBuckets][4]*big.Int
157}
158
159// RollupEventUpdateBucketsParameters is an event of the Rollup Smart Contract
160type RollupEventUpdateBucketsParameters struct {
161	// ArrayBuckets [common.RollupConstNumBuckets][4]*big.Int
162	ArrayBuckets [common.RollupConstNumBuckets]RollupUpdateBucketsParameters
163	SafeMode     bool
164}
165
166// RollupEventUpdateTokenExchange is an event of the Rollup Smart Contract
167type RollupEventUpdateTokenExchange struct {
168	AddressArray []ethCommon.Address
169	ValueArray   []uint64
170}
171
172// RollupEventSafeMode is an event of the Rollup Smart Contract
173type RollupEventSafeMode struct {
174}
175
176// RollupEvents is the list of events in a block of the Rollup Smart Contract
177type RollupEvents struct {
178	L1UserTx                    []RollupEventL1UserTx
179	AddToken                    []RollupEventAddToken
180	ForgeBatch                  []RollupEventForgeBatch
181	UpdateForgeL1L2BatchTimeout []RollupEventUpdateForgeL1L2BatchTimeout
182	UpdateFeeAddToken           []RollupEventUpdateFeeAddToken
183	Withdraw                    []RollupEventWithdraw
184	UpdateWithdrawalDelay       []RollupEventUpdateWithdrawalDelay
185	UpdateBucketWithdraw        []RollupEventUpdateBucketWithdraw
186	UpdateBucketsParameters     []RollupEventUpdateBucketsParameters
187	UpdateTokenExchange         []RollupEventUpdateTokenExchange
188	SafeMode                    []RollupEventSafeMode
189}
190
191// NewRollupEvents creates an empty RollupEvents with the slices initialized.
192func NewRollupEvents() RollupEvents {
193	return RollupEvents{
194		L1UserTx:                    make([]RollupEventL1UserTx, 0),
195		AddToken:                    make([]RollupEventAddToken, 0),
196		ForgeBatch:                  make([]RollupEventForgeBatch, 0),
197		UpdateForgeL1L2BatchTimeout: make([]RollupEventUpdateForgeL1L2BatchTimeout, 0),
198		UpdateFeeAddToken:           make([]RollupEventUpdateFeeAddToken, 0),
199		Withdraw:                    make([]RollupEventWithdraw, 0),
200	}
201}
202
203// RollupForgeBatchArgs are the arguments to the ForgeBatch function in the Rollup Smart Contract
204type RollupForgeBatchArgs struct {
205	NewLastIdx            int64
206	NewStRoot             *big.Int
207	NewExitRoot           *big.Int
208	L1UserTxs             []common.L1Tx
209	L1CoordinatorTxs      []common.L1Tx
210	L1CoordinatorTxsAuths [][]byte // Authorization for accountCreations for each L1CoordinatorTx
211	L2TxsData             []common.L2Tx
212	FeeIdxCoordinator     []common.Idx
213	// Circuit selector
214	VerifierIdx uint8
215	L1Batch     bool
216	ProofA      [2]*big.Int
217	ProofB      [2][2]*big.Int
218	ProofC      [2]*big.Int
219}
220
221// RollupForgeBatchArgsAux are the arguments to the ForgeBatch function in the Rollup Smart Contract
222type rollupForgeBatchArgsAux struct {
223	NewLastIdx             *big.Int
224	NewStRoot              *big.Int
225	NewExitRoot            *big.Int
226	EncodedL1CoordinatorTx []byte
227	L1L2TxsData            []byte
228	FeeIdxCoordinator      []byte
229	// Circuit selector
230	VerifierIdx uint8
231	L1Batch     bool
232	ProofA      [2]*big.Int
233	ProofB      [2][2]*big.Int
234	ProofC      [2]*big.Int
235}
236
237// RollupInterface is the inteface to to Rollup Smart Contract
238type RollupInterface interface {
239	//
240	// Smart Contract Methods
241	//
242
243	// Public Functions
244
245	RollupForgeBatch(*RollupForgeBatchArgs) (*types.Transaction, error)
246	RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (*types.Transaction, error)
247
248	RollupWithdrawMerkleProof(babyPubKey babyjub.PublicKeyComp, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error)
249	RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error)
250
251	RollupL1UserTxERC20ETH(fromBJJ babyjub.PublicKeyComp, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error)
252	RollupL1UserTxERC20Permit(fromBJJ babyjub.PublicKeyComp, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error)
253
254	// Governance Public Functions
255	RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (*types.Transaction, error)
256	RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (*types.Transaction, error)
257
258	// Viewers
259	RollupRegisterTokensCount() (*big.Int, error)
260	RollupLastForgedBatch() (int64, error)
261
262	//
263	// Smart Contract Status
264	//
265
266	RollupConstants() (*common.RollupConstants, error)
267	RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error)
268	RollupForgeBatchArgs(ethCommon.Hash, uint16) (*RollupForgeBatchArgs, *ethCommon.Address, error)
269	RollupEventInit() (*RollupEventInitialize, int64, error)
270}
271
272//
273// Implementation
274//
275
276// RollupClient is the implementation of the interface to the Rollup Smart Contract in ethereum.
277type RollupClient struct {
278	client      *EthereumClient
279	chainID     *big.Int
280	address     ethCommon.Address
281	tokenHEZCfg TokenConfig
282	hermez      *Hermez.Hermez
283	tokenHEZ    *HEZ.HEZ
284	contractAbi abi.ABI
285	opts        *bind.CallOpts
286	consts      *common.RollupConstants
287}
288
289// NewRollupClient creates a new RollupClient
290func NewRollupClient(client *EthereumClient, address ethCommon.Address, tokenHEZCfg TokenConfig) (*RollupClient, error) {
291	contractAbi, err := abi.JSON(strings.NewReader(string(Hermez.HermezABI)))
292	if err != nil {
293		return nil, tracerr.Wrap(err)
294	}
295	hermez, err := Hermez.NewHermez(address, client.Client())
296	if err != nil {
297		return nil, tracerr.Wrap(err)
298	}
299	tokenHEZ, err := HEZ.NewHEZ(tokenHEZCfg.Address, client.Client())
300	if err != nil {
301		return nil, tracerr.Wrap(err)
302	}
303	chainID, err := client.EthChainID()
304	if err != nil {
305		return nil, tracerr.Wrap(err)
306	}
307	c := &RollupClient{
308		client:      client,
309		chainID:     chainID,
310		address:     address,
311		tokenHEZCfg: tokenHEZCfg,
312		hermez:      hermez,
313		tokenHEZ:    tokenHEZ,
314		contractAbi: contractAbi,
315		opts:        newCallOpts(),
316	}
317	consts, err := c.RollupConstants()
318	if err != nil {
319		return nil, tracerr.Wrap(err)
320	}
321	c.consts = consts
322	return c, nil
323}
324
325// RollupForgeBatch is the interface to call the smart contract function
326func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (tx *types.Transaction, err error) {
327	if tx, err = c.client.CallAuth(
328		1000000, //nolint:gomnd
329		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
330			nLevels := c.consts.Verifiers[args.VerifierIdx].NLevels
331			lenBytes := nLevels / 8 //nolint:gomnd
332			newLastIdx := big.NewInt(int64(args.NewLastIdx))
333			// L1CoordinatorBytes
334			var l1CoordinatorBytes []byte
335			for i := 0; i < len(args.L1CoordinatorTxs); i++ {
336				l1 := args.L1CoordinatorTxs[i]
337				bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i])
338				if err != nil {
339					return nil, tracerr.Wrap(err)
340				}
341				l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...)
342			}
343			// L1L2TxData
344			var l1l2TxData []byte
345			for i := 0; i < len(args.L1UserTxs); i++ {
346				l1User := args.L1UserTxs[i]
347				bytesl1User, err := l1User.BytesDataAvailability(uint32(nLevels))
348				if err != nil {
349					return nil, tracerr.Wrap(err)
350				}
351				l1l2TxData = append(l1l2TxData, bytesl1User[:]...)
352			}
353			for i := 0; i < len(args.L1CoordinatorTxs); i++ {
354				l1Coord := args.L1CoordinatorTxs[i]
355				bytesl1Coord, err := l1Coord.BytesDataAvailability(uint32(nLevels))
356				if err != nil {
357					return nil, tracerr.Wrap(err)
358				}
359				l1l2TxData = append(l1l2TxData, bytesl1Coord[:]...)
360			}
361			for i := 0; i < len(args.L2TxsData); i++ {
362				l2 := args.L2TxsData[i]
363				bytesl2, err := l2.BytesDataAvailability(uint32(nLevels))
364				if err != nil {
365					return nil, tracerr.Wrap(err)
366				}
367				l1l2TxData = append(l1l2TxData, bytesl2[:]...)
368			}
369			// FeeIdxCoordinator
370			var feeIdxCoordinator []byte
371			if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator {
372				return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v",
373					common.RollupConstMaxFeeIdxCoordinator))
374			}
375			for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ {
376				feeIdx := common.Idx(0)
377				if i < len(args.FeeIdxCoordinator) {
378					feeIdx = args.FeeIdxCoordinator[i]
379				}
380				bytesFeeIdx, err := feeIdx.Bytes()
381				if err != nil {
382					return nil, tracerr.Wrap(err)
383				}
384				feeIdxCoordinator = append(feeIdxCoordinator, bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...)
385			}
386			return c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, l1CoordinatorBytes, l1l2TxData, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, args.ProofA, args.ProofB, args.ProofC)
387		},
388	); err != nil {
389		return nil, tracerr.Wrap(fmt.Errorf("Failed forge batch: %w", err))
390	}
391	return tx, nil
392}
393
394// RollupAddToken is the interface to call the smart contract function.
395// `feeAddToken` is the amount of HEZ tokens that will be paid to add the
396// token.  `feeAddToken` must match the public value of the smart contract.
397func (c *RollupClient) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (tx *types.Transaction, err error) {
398	if tx, err = c.client.CallAuth(
399		0,
400		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
401			owner := c.client.account.Address
402			spender := c.address
403			nonce, err := c.tokenHEZ.Nonces(c.opts, owner)
404			if err != nil {
405				return nil, tracerr.Wrap(err)
406			}
407			tokenName := c.tokenHEZCfg.Name
408			tokenAddr := c.tokenHEZCfg.Address
409			digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, feeAddToken, nonce, deadline, tokenName)
410			signature, _ := c.client.ks.SignHash(*c.client.account, digest)
411			permit := createPermit(owner, spender, feeAddToken, deadline, digest, signature)
412
413			return c.hermez.AddToken(auth, tokenAddress, permit)
414		},
415	); err != nil {
416		return nil, tracerr.Wrap(fmt.Errorf("Failed add Token %w", err))
417	}
418	return tx, nil
419}
420
421// RollupWithdrawMerkleProof is the interface to call the smart contract function
422func (c *RollupClient) RollupWithdrawMerkleProof(fromBJJ babyjub.PublicKeyComp, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) {
423	if tx, err = c.client.CallAuth(
424		0,
425		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
426			pkCompB := common.SwapEndianness(fromBJJ[:])
427			babyPubKey := new(big.Int).SetBytes(pkCompB)
428			numExitRootB := uint32(numExitRoot)
429			idxBig := big.NewInt(idx)
430			return c.hermez.WithdrawMerkleProof(auth, tokenID, amount, babyPubKey, numExitRootB, siblings, idxBig, instantWithdraw)
431		},
432	); err != nil {
433		return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawMerkleProof: %w", err))
434	}
435	return tx, nil
436}
437
438// RollupWithdrawCircuit is the interface to call the smart contract function
439func (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) {
440	log.Error("TODO")
441	return nil, tracerr.Wrap(errTODO)
442}
443
444// RollupL1UserTxERC20ETH is the interface to call the smart contract function
445func (c *RollupClient) RollupL1UserTxERC20ETH(fromBJJ babyjub.PublicKeyComp, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (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			var babyPubKey *big.Int
450			if fromBJJ != common.EmptyBJJComp {
451				pkCompB := common.SwapEndianness(fromBJJ[:])
452				babyPubKey = new(big.Int).SetBytes(pkCompB)
453			} else {
454				babyPubKey = big.NewInt(0)
455			}
456			fromIdxBig := big.NewInt(fromIdx)
457			toIdxBig := big.NewInt(toIdx)
458			depositAmountF, err := common.NewFloat16(depositAmount)
459			if err != nil {
460				return nil, tracerr.Wrap(err)
461			}
462			amountF, err := common.NewFloat16(amount)
463			if err != nil {
464				return nil, tracerr.Wrap(err)
465			}
466			if tokenID == 0 {
467				auth.Value = depositAmount
468			}
469			var permit []byte
470			return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(depositAmountF),
471				uint16(amountF), tokenID, toIdxBig, permit)
472		},
473	); err != nil {
474		return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20/ETH: %w", err))
475	}
476	return tx, nil
477}
478
479// RollupL1UserTxERC20Permit is the interface to call the smart contract function
480func (c *RollupClient) RollupL1UserTxERC20Permit(fromBJJ babyjub.PublicKeyComp, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error) {
481	if tx, err = c.client.CallAuth(
482		0,
483		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
484			var babyPubKey *big.Int
485			if fromBJJ != common.EmptyBJJComp {
486				pkCompB := common.SwapEndianness(fromBJJ[:])
487				babyPubKey = new(big.Int).SetBytes(pkCompB)
488			} else {
489				babyPubKey = big.NewInt(0)
490			}
491			fromIdxBig := big.NewInt(fromIdx)
492			toIdxBig := big.NewInt(toIdx)
493			depositAmountF, err := common.NewFloat16(depositAmount)
494			if err != nil {
495				return nil, tracerr.Wrap(err)
496			}
497			amountF, err := common.NewFloat16(amount)
498			if err != nil {
499				return nil, tracerr.Wrap(err)
500			}
501			if tokenID == 0 {
502				auth.Value = depositAmount
503			}
504			owner := c.client.account.Address
505			spender := c.address
506			nonce, err := c.tokenHEZ.Nonces(c.opts, owner)
507			if err != nil {
508				return nil, tracerr.Wrap(err)
509			}
510			tokenName := c.tokenHEZCfg.Name
511			tokenAddr := c.tokenHEZCfg.Address
512			digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, amount, nonce, deadline, tokenName)
513			signature, _ := c.client.ks.SignHash(*c.client.account, digest)
514			permit := createPermit(owner, spender, amount, deadline, digest, signature)
515			return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(depositAmountF),
516				uint16(amountF), tokenID, toIdxBig, permit)
517		},
518	); err != nil {
519		return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20Permit: %w", err))
520	}
521	return tx, nil
522}
523
524// RollupRegisterTokensCount is the interface to call the smart contract function
525func (c *RollupClient) RollupRegisterTokensCount() (registerTokensCount *big.Int, err error) {
526	if err := c.client.Call(func(ec *ethclient.Client) error {
527		registerTokensCount, err = c.hermez.RegisterTokensCount(c.opts)
528		return tracerr.Wrap(err)
529	}); err != nil {
530		return nil, tracerr.Wrap(err)
531	}
532	return registerTokensCount, nil
533}
534
535// RollupLastForgedBatch is the interface to call the smart contract function
536func (c *RollupClient) RollupLastForgedBatch() (lastForgedBatch int64, err error) {
537	if err := c.client.Call(func(ec *ethclient.Client) error {
538		_lastForgedBatch, err := c.hermez.LastForgedBatch(c.opts)
539		lastForgedBatch = int64(_lastForgedBatch)
540		return tracerr.Wrap(err)
541	}); err != nil {
542		return 0, tracerr.Wrap(err)
543	}
544	return lastForgedBatch, nil
545}
546
547// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
548func (c *RollupClient) RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (tx *types.Transaction, err error) {
549	if tx, err = c.client.CallAuth(
550		0,
551		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
552			return c.hermez.UpdateForgeL1L2BatchTimeout(auth, uint8(newForgeL1L2BatchTimeout))
553		},
554	); err != nil {
555		return nil, tracerr.Wrap(fmt.Errorf("Failed update ForgeL1L2BatchTimeout: %w", err))
556	}
557	return tx, nil
558}
559
560// RollupUpdateFeeAddToken is the interface to call the smart contract function
561func (c *RollupClient) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
562	if tx, err = c.client.CallAuth(
563		0,
564		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
565			return c.hermez.UpdateFeeAddToken(auth, newFeeAddToken)
566		},
567	); err != nil {
568		return nil, tracerr.Wrap(fmt.Errorf("Failed update FeeAddToken: %w", err))
569	}
570	return tx, nil
571}
572
573// RollupUpdateBucketsParameters is the interface to call the smart contract function
574func (c *RollupClient) RollupUpdateBucketsParameters(
575	arrayBuckets [common.RollupConstNumBuckets]RollupUpdateBucketsParameters,
576) (tx *types.Transaction, err error) {
577	params := [common.RollupConstNumBuckets][4]*big.Int{}
578	for i, bucket := range arrayBuckets {
579		params[i][0] = bucket.CeilUSD
580		params[i][1] = bucket.Withdrawals
581		params[i][2] = bucket.BlockWithdrawalRate
582		params[i][3] = bucket.MaxWithdrawals
583	}
584	if tx, err = c.client.CallAuth(
585		12500000, //nolint:gomnd
586		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
587			return c.hermez.UpdateBucketsParameters(auth, params)
588		},
589	); err != nil {
590		return nil, tracerr.Wrap(fmt.Errorf("Failed update Buckets Parameters: %w", err))
591	}
592	return tx, nil
593}
594
595// RollupUpdateTokenExchange is the interface to call the smart contract function
596func (c *RollupClient) RollupUpdateTokenExchange(addressArray []ethCommon.Address, valueArray []uint64) (tx *types.Transaction, err error) {
597	if tx, err = c.client.CallAuth(
598		0,
599		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
600			return c.hermez.UpdateTokenExchange(auth, addressArray, valueArray)
601		},
602	); err != nil {
603		return nil, tracerr.Wrap(fmt.Errorf("Failed update Token Exchange: %w", err))
604	}
605	return tx, nil
606}
607
608// RollupUpdateWithdrawalDelay is the interface to call the smart contract function
609func (c *RollupClient) RollupUpdateWithdrawalDelay(newWithdrawalDelay int64) (tx *types.Transaction, err error) {
610	if tx, err = c.client.CallAuth(
611		0,
612		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
613			return c.hermez.UpdateWithdrawalDelay(auth, uint64(newWithdrawalDelay))
614		},
615	); err != nil {
616		return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawalDelay: %w", err))
617	}
618	return tx, nil
619}
620
621// RollupSafeMode is the interface to call the smart contract function
622func (c *RollupClient) RollupSafeMode() (tx *types.Transaction, err error) {
623	if tx, err = c.client.CallAuth(
624		0,
625		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
626			return c.hermez.SafeMode(auth)
627		},
628	); err != nil {
629		return nil, tracerr.Wrap(fmt.Errorf("Failed update Safe Mode: %w", err))
630	}
631	return tx, nil
632}
633
634// RollupInstantWithdrawalViewer is the interface to call the smart contract function
635func (c *RollupClient) RollupInstantWithdrawalViewer(tokenAddress ethCommon.Address, amount *big.Int) (instantAllowed bool, err error) {
636	if err := c.client.Call(func(ec *ethclient.Client) error {
637		instantAllowed, err = c.hermez.InstantWithdrawalViewer(c.opts, tokenAddress, amount)
638		return tracerr.Wrap(err)
639	}); err != nil {
640		return false, tracerr.Wrap(err)
641	}
642	return instantAllowed, nil
643}
644
645// RollupConstants returns the Constants of the Rollup Smart Contract
646func (c *RollupClient) RollupConstants() (rollupConstants *common.RollupConstants, err error) {
647	rollupConstants = new(common.RollupConstants)
648	if err := c.client.Call(func(ec *ethclient.Client) error {
649		absoluteMaxL1L2BatchTimeout, err := c.hermez.ABSOLUTEMAXL1L2BATCHTIMEOUT(c.opts)
650		if err != nil {
651			return tracerr.Wrap(err)
652		}
653		rollupConstants.AbsoluteMaxL1L2BatchTimeout = int64(absoluteMaxL1L2BatchTimeout)
654		rollupConstants.TokenHEZ, err = c.hermez.TokenHEZ(c.opts)
655		if err != nil {
656			return tracerr.Wrap(err)
657		}
658		for i := int64(0); i < int64(common.LenVerifiers); i++ {
659			var newRollupVerifier common.RollupVerifierStruct
660			rollupVerifier, err := c.hermez.RollupVerifiers(c.opts, big.NewInt(i))
661			if err != nil {
662				return tracerr.Wrap(err)
663			}
664			newRollupVerifier.MaxTx = rollupVerifier.MaxTx.Int64()
665			newRollupVerifier.NLevels = rollupVerifier.NLevels.Int64()
666			rollupConstants.Verifiers = append(rollupConstants.Verifiers, newRollupVerifier)
667		}
668		rollupConstants.HermezAuctionContract, err = c.hermez.HermezAuctionContract(c.opts)
669		if err != nil {
670			return tracerr.Wrap(err)
671		}
672		rollupConstants.HermezGovernanceAddress, err = c.hermez.HermezGovernanceAddress(c.opts)
673		if err != nil {
674			return tracerr.Wrap(err)
675		}
676		rollupConstants.WithdrawDelayerContract, err = c.hermez.WithdrawDelayerContract(c.opts)
677		return tracerr.Wrap(err)
678	}); err != nil {
679		return nil, tracerr.Wrap(err)
680	}
681	return rollupConstants, nil
682}
683
684var (
685	logHermezL1UserTxEvent               = crypto.Keccak256Hash([]byte("L1UserTxEvent(uint32,uint8,bytes)"))
686	logHermezAddToken                    = crypto.Keccak256Hash([]byte("AddToken(address,uint32)"))
687	logHermezForgeBatch                  = crypto.Keccak256Hash([]byte("ForgeBatch(uint32,uint16)"))
688	logHermezUpdateForgeL1L2BatchTimeout = crypto.Keccak256Hash([]byte("UpdateForgeL1L2BatchTimeout(uint8)"))
689	logHermezUpdateFeeAddToken           = crypto.Keccak256Hash([]byte("UpdateFeeAddToken(uint256)"))
690	logHermezWithdrawEvent               = crypto.Keccak256Hash([]byte("WithdrawEvent(uint48,uint32,bool)"))
691	logHermezUpdateBucketWithdraw        = crypto.Keccak256Hash([]byte("UpdateBucketWithdraw(uint8,uint256,uint256)"))
692	logHermezUpdateWithdrawalDelay       = crypto.Keccak256Hash([]byte("UpdateWithdrawalDelay(uint64)"))
693	logHermezUpdateBucketsParameters     = crypto.Keccak256Hash([]byte("UpdateBucketsParameters(uint256[4][" +
694		strconv.Itoa(common.RollupConstNumBuckets) + "])"))
695	logHermezUpdateTokenExchange = crypto.Keccak256Hash([]byte("UpdateTokenExchange(address[],uint64[])"))
696	logHermezSafeMode            = crypto.Keccak256Hash([]byte("SafeMode()"))
697	logHermezInitialize          = crypto.Keccak256Hash([]byte("InitializeHermezEvent(uint8,uint256,uint64)"))
698)
699
700// RollupEventInit returns the initialize event with its corresponding block number
701func (c *RollupClient) RollupEventInit() (*RollupEventInitialize, int64, error) {
702	query := ethereum.FilterQuery{
703		Addresses: []ethCommon.Address{
704			c.address,
705		},
706		Topics: [][]ethCommon.Hash{{logHermezInitialize}},
707	}
708	logs, err := c.client.client.FilterLogs(context.Background(), query)
709	if err != nil {
710		return nil, 0, tracerr.Wrap(err)
711	}
712	if len(logs) != 1 {
713		return nil, 0, tracerr.Wrap(fmt.Errorf("no event of type InitializeHermezEvent found"))
714	}
715	vLog := logs[0]
716	if vLog.Topics[0] != logHermezInitialize {
717		return nil, 0, tracerr.Wrap(fmt.Errorf("event is not InitializeHermezEvent"))
718	}
719
720	var rollupInit RollupEventInitialize
721	if err := c.contractAbi.UnpackIntoInterface(&rollupInit, "InitializeHermezEvent", vLog.Data); err != nil {
722		return nil, 0, tracerr.Wrap(err)
723	}
724	return &rollupInit, int64(vLog.BlockNumber), tracerr.Wrap(err)
725}
726
727// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
728func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) {
729	var rollupEvents RollupEvents
730	var blockHash *ethCommon.Hash
731
732	query := ethereum.FilterQuery{
733		FromBlock: big.NewInt(blockNum),
734		ToBlock:   big.NewInt(blockNum),
735		Addresses: []ethCommon.Address{
736			c.address,
737		},
738		BlockHash: nil,
739		Topics:    [][]ethCommon.Hash{},
740	}
741	logs, err := c.client.client.FilterLogs(context.Background(), query)
742	if err != nil {
743		return nil, nil, tracerr.Wrap(err)
744	}
745	if len(logs) > 0 {
746		blockHash = &logs[0].BlockHash
747	}
748	for _, vLog := range logs {
749		if vLog.BlockHash != *blockHash {
750			log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String())
751			return nil, nil, tracerr.Wrap(ErrBlockHashMismatchEvent)
752		}
753		switch vLog.Topics[0] {
754		case logHermezL1UserTxEvent:
755			var L1UserTxAux rollupEventL1UserTxAux
756			var L1UserTx RollupEventL1UserTx
757			err := c.contractAbi.UnpackIntoInterface(&L1UserTxAux, "L1UserTxEvent", vLog.Data)
758			if err != nil {
759				return nil, nil, tracerr.Wrap(err)
760			}
761			L1Tx, err := common.L1UserTxFromBytes(L1UserTxAux.L1UserTx)
762			if err != nil {
763				return nil, nil, tracerr.Wrap(err)
764			}
765			toForgeL1TxsNum := new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
766			L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
767			L1Tx.Position = int(new(big.Int).SetBytes(vLog.Topics[2][:]).Int64())
768			L1Tx.UserOrigin = true
769			L1UserTx.L1UserTx = *L1Tx
770			rollupEvents.L1UserTx = append(rollupEvents.L1UserTx, L1UserTx)
771		case logHermezAddToken:
772			var addToken RollupEventAddToken
773			err := c.contractAbi.UnpackIntoInterface(&addToken, "AddToken", vLog.Data)
774			if err != nil {
775				return nil, nil, tracerr.Wrap(err)
776			}
777			addToken.TokenAddress = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
778			rollupEvents.AddToken = append(rollupEvents.AddToken, addToken)
779		case logHermezForgeBatch:
780			var forgeBatch RollupEventForgeBatch
781			err := c.contractAbi.UnpackIntoInterface(&forgeBatch, "ForgeBatch", vLog.Data)
782			if err != nil {
783				return nil, nil, tracerr.Wrap(err)
784			}
785			forgeBatch.BatchNum = new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
786			forgeBatch.EthTxHash = vLog.TxHash
787			// forgeBatch.Sender = vLog.Address
788			rollupEvents.ForgeBatch = append(rollupEvents.ForgeBatch, forgeBatch)
789		case logHermezUpdateForgeL1L2BatchTimeout:
790			var updateForgeL1L2BatchTimeout struct {
791				NewForgeL1L2BatchTimeout uint8
792			}
793			err := c.contractAbi.UnpackIntoInterface(&updateForgeL1L2BatchTimeout, "UpdateForgeL1L2BatchTimeout", vLog.Data)
794			if err != nil {
795				return nil, nil, tracerr.Wrap(err)
796			}
797			rollupEvents.UpdateForgeL1L2BatchTimeout = append(rollupEvents.UpdateForgeL1L2BatchTimeout,
798				RollupEventUpdateForgeL1L2BatchTimeout{
799					NewForgeL1L2BatchTimeout: int64(updateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout),
800				})
801		case logHermezUpdateFeeAddToken:
802			var updateFeeAddToken RollupEventUpdateFeeAddToken
803			err := c.contractAbi.UnpackIntoInterface(&updateFeeAddToken, "UpdateFeeAddToken", vLog.Data)
804			if err != nil {
805				return nil, nil, tracerr.Wrap(err)
806			}
807			rollupEvents.UpdateFeeAddToken = append(rollupEvents.UpdateFeeAddToken, updateFeeAddToken)
808		case logHermezWithdrawEvent:
809			var withdraw RollupEventWithdraw
810			withdraw.Idx = new(big.Int).SetBytes(vLog.Topics[1][:]).Uint64()
811			withdraw.NumExitRoot = new(big.Int).SetBytes(vLog.Topics[2][:]).Uint64()
812			instantWithdraw := new(big.Int).SetBytes(vLog.Topics[3][:]).Uint64()
813			if instantWithdraw == 1 {
814				withdraw.InstantWithdraw = true
815			}
816			withdraw.TxHash = vLog.TxHash
817			rollupEvents.Withdraw = append(rollupEvents.Withdraw, withdraw)
818		case logHermezUpdateBucketWithdraw:
819			var updateBucketWithdrawAux rollupEventUpdateBucketWithdrawAux
820			var updateBucketWithdraw RollupEventUpdateBucketWithdraw
821			err := c.contractAbi.UnpackIntoInterface(&updateBucketWithdrawAux, "UpdateBucketWithdraw", vLog.Data)
822			if err != nil {
823				return nil, nil, tracerr.Wrap(err)
824			}
825			updateBucketWithdraw.Withdrawals = updateBucketWithdrawAux.Withdrawals
826			updateBucketWithdraw.NumBucket = int(new(big.Int).SetBytes(vLog.Topics[1][:]).Int64())
827			updateBucketWithdraw.BlockStamp = new(big.Int).SetBytes(vLog.Topics[2][:]).Int64()
828			rollupEvents.UpdateBucketWithdraw = append(rollupEvents.UpdateBucketWithdraw, updateBucketWithdraw)
829
830		case logHermezUpdateWithdrawalDelay:
831			var withdrawalDelay RollupEventUpdateWithdrawalDelay
832			err := c.contractAbi.UnpackIntoInterface(&withdrawalDelay, "UpdateWithdrawalDelay", vLog.Data)
833			if err != nil {
834				return nil, nil, tracerr.Wrap(err)
835			}
836			rollupEvents.UpdateWithdrawalDelay = append(rollupEvents.UpdateWithdrawalDelay, withdrawalDelay)
837		case logHermezUpdateBucketsParameters:
838			var bucketsParametersAux rollupEventUpdateBucketsParametersAux
839			var bucketsParameters RollupEventUpdateBucketsParameters
840			err := c.contractAbi.UnpackIntoInterface(&bucketsParametersAux, "UpdateBucketsParameters", vLog.Data)
841			if err != nil {
842				return nil, nil, tracerr.Wrap(err)
843			}
844			for i, bucket := range bucketsParametersAux.ArrayBuckets {
845				bucketsParameters.ArrayBuckets[i].CeilUSD = bucket[0]
846				bucketsParameters.ArrayBuckets[i].Withdrawals = bucket[1]
847				bucketsParameters.ArrayBuckets[i].BlockWithdrawalRate = bucket[2]
848				bucketsParameters.ArrayBuckets[i].MaxWithdrawals = bucket[3]
849			}
850			rollupEvents.UpdateBucketsParameters = append(rollupEvents.UpdateBucketsParameters, bucketsParameters)
851		case logHermezUpdateTokenExchange:
852			var tokensExchange RollupEventUpdateTokenExchange
853			err := c.contractAbi.UnpackIntoInterface(&tokensExchange, "UpdateTokenExchange", vLog.Data)
854			if err != nil {
855				return nil, nil, tracerr.Wrap(err)
856			}
857			rollupEvents.UpdateTokenExchange = append(rollupEvents.UpdateTokenExchange, tokensExchange)
858		case logHermezSafeMode:
859			var safeMode RollupEventSafeMode
860			rollupEvents.SafeMode = append(rollupEvents.SafeMode, safeMode)
861			// Also add an UpdateBucketsParameter with
862			// SafeMode=true to keep the order between `safeMode`
863			// and `UpdateBucketsParameters`
864			bucketsParameters := RollupEventUpdateBucketsParameters{
865				SafeMode: true,
866			}
867			for i := range bucketsParameters.ArrayBuckets {
868				bucketsParameters.ArrayBuckets[i].CeilUSD = big.NewInt(0)
869				bucketsParameters.ArrayBuckets[i].Withdrawals = big.NewInt(0)
870				bucketsParameters.ArrayBuckets[i].BlockWithdrawalRate = big.NewInt(0)
871				bucketsParameters.ArrayBuckets[i].MaxWithdrawals = big.NewInt(0)
872			}
873			rollupEvents.UpdateBucketsParameters = append(rollupEvents.UpdateBucketsParameters,
874				bucketsParameters)
875		}
876	}
877	return &rollupEvents, blockHash, nil
878}
879
880// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the
881// Rollup Smart Contract in the given transaction, and the sender address.
882func (c *RollupClient) RollupForgeBatchArgs(ethTxHash ethCommon.Hash, l1UserTxsLen uint16) (*RollupForgeBatchArgs, *ethCommon.Address, error) {
883	tx, _, err := c.client.client.TransactionByHash(context.Background(), ethTxHash)
884	if err != nil {
885		return nil, nil, tracerr.Wrap(err)
886	}
887	txData := tx.Data()
888
889	method, err := c.contractAbi.MethodById(txData[:4])
890	if err != nil {
891		return nil, nil, tracerr.Wrap(err)
892	}
893	receipt, err := c.client.client.TransactionReceipt(context.Background(), ethTxHash)
894	if err != nil {
895		return nil, nil, tracerr.Wrap(err)
896	}
897	sender, err := c.client.client.TransactionSender(context.Background(), tx, receipt.Logs[0].BlockHash, receipt.Logs[0].Index)
898	if err != nil {
899		return nil, nil, tracerr.Wrap(err)
900	}
901	var aux rollupForgeBatchArgsAux
902	if values, err := method.Inputs.Unpack(txData[4:]); err != nil {
903		return nil, nil, tracerr.Wrap(err)
904	} else if err := method.Inputs.Copy(&aux, values); err != nil {
905		return nil, nil, tracerr.Wrap(err)
906	}
907	rollupForgeBatchArgs := RollupForgeBatchArgs{
908		L1Batch:               aux.L1Batch,
909		NewExitRoot:           aux.NewExitRoot,
910		NewLastIdx:            aux.NewLastIdx.Int64(),
911		NewStRoot:             aux.NewStRoot,
912		ProofA:                aux.ProofA,
913		ProofB:                aux.ProofB,
914		ProofC:                aux.ProofC,
915		VerifierIdx:           aux.VerifierIdx,
916		L1CoordinatorTxs:      []common.L1Tx{},
917		L1CoordinatorTxsAuths: [][]byte{},
918		L2TxsData:             []common.L2Tx{},
919		FeeIdxCoordinator:     []common.Idx{},
920	}
921	nLevels := c.consts.Verifiers[rollupForgeBatchArgs.VerifierIdx].NLevels
922	lenL1L2TxsBytes := int((nLevels/8)*2 + 2 + 1)
923	numBytesL1TxUser := int(l1UserTxsLen) * lenL1L2TxsBytes
924	numTxsL1Coord := len(aux.EncodedL1CoordinatorTx) / common.L1CoordinatorTxBytesLen
925	numBytesL1TxCoord := numTxsL1Coord * lenL1L2TxsBytes
926	numBeginL2Tx := numBytesL1TxCoord + numBytesL1TxUser
927	l1UserTxsData := []byte{}
928	if l1UserTxsLen > 0 {
929		l1UserTxsData = aux.L1L2TxsData[:numBytesL1TxUser]
930	}
931	for i := 0; i < int(l1UserTxsLen); i++ {
932		l1Tx, err := common.L1TxFromDataAvailability(l1UserTxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], uint32(nLevels))
933		if err != nil {
934			return nil, nil, tracerr.Wrap(err)
935		}
936		rollupForgeBatchArgs.L1UserTxs = append(rollupForgeBatchArgs.L1UserTxs, *l1Tx)
937	}
938	l2TxsData := []byte{}
939	if numBeginL2Tx < len(aux.L1L2TxsData) {
940		l2TxsData = aux.L1L2TxsData[numBeginL2Tx:]
941	}
942	numTxsL2 := len(l2TxsData) / lenL1L2TxsBytes
943	for i := 0; i < numTxsL2; i++ {
944		l2Tx, err := common.L2TxFromBytesDataAvailability(l2TxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], int(nLevels))
945		if err != nil {
946			return nil, nil, tracerr.Wrap(err)
947		}
948		rollupForgeBatchArgs.L2TxsData = append(rollupForgeBatchArgs.L2TxsData, *l2Tx)
949	}
950	for i := 0; i < numTxsL1Coord; i++ {
951		bytesL1Coordinator := aux.EncodedL1CoordinatorTx[i*common.L1CoordinatorTxBytesLen : (i+1)*common.L1CoordinatorTxBytesLen]
952		var signature []byte
953		v := bytesL1Coordinator[0]
954		s := bytesL1Coordinator[1:33]
955		r := bytesL1Coordinator[33:65]
956		signature = append(signature, r[:]...)
957		signature = append(signature, s[:]...)
958		signature = append(signature, v)
959		l1Tx, err := common.L1CoordinatorTxFromBytes(bytesL1Coordinator, c.chainID, c.address)
960		if err != nil {
961			return nil, nil, tracerr.Wrap(err)
962		}
963		rollupForgeBatchArgs.L1CoordinatorTxs = append(rollupForgeBatchArgs.L1CoordinatorTxs, *l1Tx)
964		rollupForgeBatchArgs.L1CoordinatorTxsAuths = append(rollupForgeBatchArgs.L1CoordinatorTxsAuths, signature)
965	}
966	lenFeeIdxCoordinatorBytes := int(nLevels / 8) //nolint:gomnd
967	numFeeIdxCoordinator := len(aux.FeeIdxCoordinator) / lenFeeIdxCoordinatorBytes
968	for i := 0; i < numFeeIdxCoordinator; i++ {
969		var paddedFeeIdx [6]byte
970		// TODO: This check is not necessary: the first case will always work.  Test it before removing the if.
971		if lenFeeIdxCoordinatorBytes < common.IdxBytesLen {
972			copy(paddedFeeIdx[6-lenFeeIdxCoordinatorBytes:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
973		} else {
974			copy(paddedFeeIdx[:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
975		}
976		feeIdxCoordinator, err := common.IdxFromBytes(paddedFeeIdx[:])
977		if err != nil {
978			return nil, nil, tracerr.Wrap(err)
979		}
980		if feeIdxCoordinator != common.Idx(0) {
981			rollupForgeBatchArgs.FeeIdxCoordinator = append(rollupForgeBatchArgs.FeeIdxCoordinator, feeIdxCoordinator)
982		}
983	}
984	return &rollupForgeBatchArgs, &sender, nil
985}