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.PublicKey, 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.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error)
252 RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, 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}
287
288// NewRollupClient creates a new RollupClient
289func NewRollupClient(client *EthereumClient, address ethCommon.Address, tokenHEZCfg TokenConfig) (*RollupClient, error) {
290 contractAbi, err := abi.JSON(strings.NewReader(string(Hermez.HermezABI)))
291 if err != nil {
292 return nil, tracerr.Wrap(err)
293 }
294 hermez, err := Hermez.NewHermez(address, client.Client())
295 if err != nil {
296 return nil, tracerr.Wrap(err)
297 }
298 tokenHEZ, err := HEZ.NewHEZ(tokenHEZCfg.Address, client.Client())
299 if err != nil {
300 return nil, tracerr.Wrap(err)
301 }
302 chainID, err := client.client.ChainID(context.Background())
303 if err != nil {
304 return nil, tracerr.Wrap(err)
305 }
306 return &RollupClient{
307 client: client,
308 chainID: chainID,
309 address: address,
310 tokenHEZCfg: tokenHEZCfg,
311 hermez: hermez,
312 tokenHEZ: tokenHEZ,
313 contractAbi: contractAbi,
314 opts: newCallOpts(),
315 }, nil
316}
317
318// RollupForgeBatch is the interface to call the smart contract function
319func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (tx *types.Transaction, err error) {
320 if tx, err = c.client.CallAuth(
321 1000000, //nolint:gomnd
322 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
323 rollupConst, err := c.RollupConstants()
324 if err != nil {
325 return nil, tracerr.Wrap(err)
326 }
327 nLevels := rollupConst.Verifiers[args.VerifierIdx].NLevels
328 lenBytes := nLevels / 8 //nolint:gomnd
329 newLastIdx := big.NewInt(int64(args.NewLastIdx))
330 // L1CoordinatorBytes
331 var l1CoordinatorBytes []byte
332 for i := 0; i < len(args.L1CoordinatorTxs); i++ {
333 l1 := args.L1CoordinatorTxs[i]
334 bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i])
335 if err != nil {
336 return nil, tracerr.Wrap(err)
337 }
338 l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...)
339 }
340 // L1L2TxData
341 var l1l2TxData []byte
342 for i := 0; i < len(args.L1UserTxs); i++ {
343 l1User := args.L1UserTxs[i]
344 bytesl1User, err := l1User.BytesDataAvailability(uint32(nLevels))
345 if err != nil {
346 return nil, tracerr.Wrap(err)
347 }
348 l1l2TxData = append(l1l2TxData, bytesl1User[:]...)
349 }
350 for i := 0; i < len(args.L1CoordinatorTxs); i++ {
351 l1Coord := args.L1CoordinatorTxs[i]
352 bytesl1Coord, err := l1Coord.BytesDataAvailability(uint32(nLevels))
353 if err != nil {
354 return nil, tracerr.Wrap(err)
355 }
356 l1l2TxData = append(l1l2TxData, bytesl1Coord[:]...)
357 }
358 for i := 0; i < len(args.L2TxsData); i++ {
359 l2 := args.L2TxsData[i]
360 bytesl2, err := l2.BytesDataAvailability(uint32(nLevels))
361 if err != nil {
362 return nil, tracerr.Wrap(err)
363 }
364 l1l2TxData = append(l1l2TxData, bytesl2[:]...)
365 }
366 // FeeIdxCoordinator
367 var feeIdxCoordinator []byte
368 if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator {
369 return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v",
370 common.RollupConstMaxFeeIdxCoordinator))
371 }
372 for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ {
373 feeIdx := common.Idx(0)
374 if i < len(args.FeeIdxCoordinator) {
375 feeIdx = args.FeeIdxCoordinator[i]
376 }
377 bytesFeeIdx, err := feeIdx.Bytes()
378 if err != nil {
379 return nil, tracerr.Wrap(err)
380 }
381 feeIdxCoordinator = append(feeIdxCoordinator, bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...)
382 }
383 return c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, l1CoordinatorBytes, l1l2TxData, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, args.ProofA, args.ProofB, args.ProofC)
384 },
385 ); err != nil {
386 return nil, tracerr.Wrap(fmt.Errorf("Failed forge batch: %w", err))
387 }
388 return tx, nil
389}
390
391// RollupAddToken is the interface to call the smart contract function.
392// `feeAddToken` is the amount of HEZ tokens that will be paid to add the
393// token. `feeAddToken` must match the public value of the smart contract.
394func (c *RollupClient) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (tx *types.Transaction, err error) {
395 if tx, err = c.client.CallAuth(
396 0,
397 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
398 owner := c.client.account.Address
399 spender := c.address
400 nonce, err := c.tokenHEZ.Nonces(c.opts, owner)
401 if err != nil {
402 return nil, tracerr.Wrap(err)
403 }
404 tokenName := c.tokenHEZCfg.Name
405 tokenAddr := c.tokenHEZCfg.Address
406 digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, feeAddToken, nonce, deadline, tokenName)
407 signature, _ := c.client.ks.SignHash(*c.client.account, digest)
408 permit := createPermit(owner, spender, feeAddToken, deadline, digest, signature)
409
410 return c.hermez.AddToken(auth, tokenAddress, permit)
411 },
412 ); err != nil {
413 return nil, tracerr.Wrap(fmt.Errorf("Failed add Token %w", err))
414 }
415 return tx, nil
416}
417
418// RollupWithdrawMerkleProof is the interface to call the smart contract function
419func (c *RollupClient) RollupWithdrawMerkleProof(fromBJJ *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (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 pkCompL := fromBJJ.Compress()
424 pkCompB := common.SwapEndianness(pkCompL[:])
425 babyPubKey := new(big.Int).SetBytes(pkCompB)
426 numExitRootB := uint32(numExitRoot)
427 idxBig := big.NewInt(idx)
428 return c.hermez.WithdrawMerkleProof(auth, tokenID, amount, babyPubKey, numExitRootB, siblings, idxBig, instantWithdraw)
429 },
430 ); err != nil {
431 return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawMerkleProof: %w", err))
432 }
433 return tx, nil
434}
435
436// RollupWithdrawCircuit is the interface to call the smart contract function
437func (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) {
438 log.Error("TODO")
439 return nil, tracerr.Wrap(errTODO)
440}
441
442// RollupL1UserTxERC20ETH is the interface to call the smart contract function
443func (c *RollupClient) RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (tx *types.Transaction, err error) {
444 if tx, err = c.client.CallAuth(
445 0,
446 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
447 var babyPubKey *big.Int
448 if fromBJJ != nil {
449 pkCompL := fromBJJ.Compress()
450 pkCompB := common.SwapEndianness(pkCompL[:])
451 babyPubKey = new(big.Int).SetBytes(pkCompB)
452 } else {
453 babyPubKey = big.NewInt(0)
454 }
455 fromIdxBig := big.NewInt(fromIdx)
456 toIdxBig := big.NewInt(toIdx)
457 depositAmountF, err := common.NewFloat16(depositAmount)
458 if err != nil {
459 return nil, tracerr.Wrap(err)
460 }
461 amountF, err := common.NewFloat16(amount)
462 if err != nil {
463 return nil, tracerr.Wrap(err)
464 }
465 if tokenID == 0 {
466 auth.Value = depositAmount
467 }
468 var permit []byte
469 return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(depositAmountF),
470 uint16(amountF), tokenID, toIdxBig, permit)
471 },
472 ); err != nil {
473 return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20/ETH: %w", err))
474 }
475 return tx, nil
476}
477
478// RollupL1UserTxERC20Permit is the interface to call the smart contract function
479func (c *RollupClient) RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error) {
480 if tx, err = c.client.CallAuth(
481 0,
482 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
483 var babyPubKey *big.Int
484 if fromBJJ != nil {
485 pkCompL := fromBJJ.Compress()
486 pkCompB := common.SwapEndianness(pkCompL[:])
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 rollupConsts, err := c.RollupConstants()
922 if err != nil {
923 return nil, nil, tracerr.Wrap(err)
924 }
925 nLevels := rollupConsts.Verifiers[rollupForgeBatchArgs.VerifierIdx].NLevels
926 lenL1L2TxsBytes := int((nLevels/8)*2 + 2 + 1)
927 numBytesL1TxUser := int(l1UserTxsLen) * lenL1L2TxsBytes
928 numTxsL1Coord := len(aux.EncodedL1CoordinatorTx) / common.L1CoordinatorTxBytesLen
929 numBytesL1TxCoord := numTxsL1Coord * lenL1L2TxsBytes
930 numBeginL2Tx := numBytesL1TxCoord + numBytesL1TxUser
931 l1UserTxsData := []byte{}
932 if l1UserTxsLen > 0 {
933 l1UserTxsData = aux.L1L2TxsData[:numBytesL1TxUser]
934 }
935 for i := 0; i < int(l1UserTxsLen); i++ {
936 l1Tx, err := common.L1TxFromDataAvailability(l1UserTxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], uint32(nLevels))
937 if err != nil {
938 return nil, nil, tracerr.Wrap(err)
939 }
940 rollupForgeBatchArgs.L1UserTxs = append(rollupForgeBatchArgs.L1UserTxs, *l1Tx)
941 }
942 l2TxsData := []byte{}
943 if numBeginL2Tx < len(aux.L1L2TxsData) {
944 l2TxsData = aux.L1L2TxsData[numBeginL2Tx:]
945 }
946 numTxsL2 := len(l2TxsData) / lenL1L2TxsBytes
947 for i := 0; i < numTxsL2; i++ {
948 l2Tx, err := common.L2TxFromBytesDataAvailability(l2TxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], int(nLevels))
949 if err != nil {
950 return nil, nil, tracerr.Wrap(err)
951 }
952 rollupForgeBatchArgs.L2TxsData = append(rollupForgeBatchArgs.L2TxsData, *l2Tx)
953 }
954 for i := 0; i < numTxsL1Coord; i++ {
955 bytesL1Coordinator := aux.EncodedL1CoordinatorTx[i*common.L1CoordinatorTxBytesLen : (i+1)*common.L1CoordinatorTxBytesLen]
956 var signature []byte
957 v := bytesL1Coordinator[0]
958 s := bytesL1Coordinator[1:33]
959 r := bytesL1Coordinator[33:65]
960 signature = append(signature, r[:]...)
961 signature = append(signature, s[:]...)
962 signature = append(signature, v)
963 l1Tx, err := common.L1CoordinatorTxFromBytes(bytesL1Coordinator, c.chainID, c.address)
964 if err != nil {
965 return nil, nil, tracerr.Wrap(err)
966 }
967 rollupForgeBatchArgs.L1CoordinatorTxs = append(rollupForgeBatchArgs.L1CoordinatorTxs, *l1Tx)
968 rollupForgeBatchArgs.L1CoordinatorTxsAuths = append(rollupForgeBatchArgs.L1CoordinatorTxsAuths, signature)
969 }
970 lenFeeIdxCoordinatorBytes := int(nLevels / 8) //nolint:gomnd
971 numFeeIdxCoordinator := len(aux.FeeIdxCoordinator) / lenFeeIdxCoordinatorBytes
972 for i := 0; i < numFeeIdxCoordinator; i++ {
973 var paddedFeeIdx [6]byte
974 // TODO: This check is not necessary: the first case will always work. Test it before removing the if.
975 if lenFeeIdxCoordinatorBytes < common.IdxBytesLen {
976 copy(paddedFeeIdx[6-lenFeeIdxCoordinatorBytes:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
977 } else {
978 copy(paddedFeeIdx[:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
979 }
980 feeIdxCoordinator, err := common.IdxFromBytes(paddedFeeIdx[:])
981 if err != nil {
982 return nil, nil, tracerr.Wrap(err)
983 }
984 if feeIdxCoordinator != common.Idx(0) {
985 rollupForgeBatchArgs.FeeIdxCoordinator = append(rollupForgeBatchArgs.FeeIdxCoordinator, feeIdxCoordinator)
986 }
987 }
988 return &rollupForgeBatchArgs, &sender, nil
989}