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, *bind.TransactOpts) (*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, auth *bind.TransactOpts) (tx *types.Transaction, err error) {
327 if auth == nil {
328 auth, err := c.client.NewAuth()
329 if err != nil {
330 return nil, err
331 }
332 auth.GasLimit = 1000000
333 }
334
335 nLevels := c.consts.Verifiers[args.VerifierIdx].NLevels
336 lenBytes := nLevels / 8 //nolint:gomnd
337 newLastIdx := big.NewInt(int64(args.NewLastIdx))
338 // L1CoordinatorBytes
339 var l1CoordinatorBytes []byte
340 for i := 0; i < len(args.L1CoordinatorTxs); i++ {
341 l1 := args.L1CoordinatorTxs[i]
342 bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i])
343 if err != nil {
344 return nil, tracerr.Wrap(err)
345 }
346 l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...)
347 }
348 // L1L2TxData
349 var l1l2TxData []byte
350 for i := 0; i < len(args.L1UserTxs); i++ {
351 l1User := args.L1UserTxs[i]
352 bytesl1User, err := l1User.BytesDataAvailability(uint32(nLevels))
353 if err != nil {
354 return nil, tracerr.Wrap(err)
355 }
356 l1l2TxData = append(l1l2TxData, bytesl1User[:]...)
357 }
358 for i := 0; i < len(args.L1CoordinatorTxs); i++ {
359 l1Coord := args.L1CoordinatorTxs[i]
360 bytesl1Coord, err := l1Coord.BytesDataAvailability(uint32(nLevels))
361 if err != nil {
362 return nil, tracerr.Wrap(err)
363 }
364 l1l2TxData = append(l1l2TxData, bytesl1Coord[:]...)
365 }
366 for i := 0; i < len(args.L2TxsData); i++ {
367 l2 := args.L2TxsData[i]
368 bytesl2, err := l2.BytesDataAvailability(uint32(nLevels))
369 if err != nil {
370 return nil, tracerr.Wrap(err)
371 }
372 l1l2TxData = append(l1l2TxData, bytesl2[:]...)
373 }
374 // FeeIdxCoordinator
375 var feeIdxCoordinator []byte
376 if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator {
377 return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v",
378 common.RollupConstMaxFeeIdxCoordinator))
379 }
380 for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ {
381 feeIdx := common.Idx(0)
382 if i < len(args.FeeIdxCoordinator) {
383 feeIdx = args.FeeIdxCoordinator[i]
384 }
385 bytesFeeIdx, err := feeIdx.Bytes()
386 if err != nil {
387 return nil, tracerr.Wrap(err)
388 }
389 feeIdxCoordinator = append(feeIdxCoordinator,
390 bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...)
391 }
392 tx, err = c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot,
393 l1CoordinatorBytes, l1l2TxData, feeIdxCoordinator, args.VerifierIdx, args.L1Batch,
394 args.ProofA, args.ProofB, args.ProofC)
395 if err != nil {
396 return nil, tracerr.Wrap(fmt.Errorf("Failed Hermez.ForgeBatch: %w", err))
397 }
398 return tx, nil
399}
400
401// RollupAddToken is the interface to call the smart contract function.
402// `feeAddToken` is the amount of HEZ tokens that will be paid to add the
403// token. `feeAddToken` must match the public value of the smart contract.
404func (c *RollupClient) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (tx *types.Transaction, err error) {
405 if tx, err = c.client.CallAuth(
406 0,
407 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
408 owner := c.client.account.Address
409 spender := c.address
410 nonce, err := c.tokenHEZ.Nonces(c.opts, owner)
411 if err != nil {
412 return nil, tracerr.Wrap(err)
413 }
414 tokenName := c.tokenHEZCfg.Name
415 tokenAddr := c.tokenHEZCfg.Address
416 digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, feeAddToken, nonce, deadline, tokenName)
417 signature, _ := c.client.ks.SignHash(*c.client.account, digest)
418 permit := createPermit(owner, spender, feeAddToken, deadline, digest, signature)
419
420 return c.hermez.AddToken(auth, tokenAddress, permit)
421 },
422 ); err != nil {
423 return nil, tracerr.Wrap(fmt.Errorf("Failed add Token %w", err))
424 }
425 return tx, nil
426}
427
428// RollupWithdrawMerkleProof is the interface to call the smart contract function
429func (c *RollupClient) RollupWithdrawMerkleProof(fromBJJ babyjub.PublicKeyComp, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) {
430 if tx, err = c.client.CallAuth(
431 0,
432 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
433 pkCompB := common.SwapEndianness(fromBJJ[:])
434 babyPubKey := new(big.Int).SetBytes(pkCompB)
435 numExitRootB := uint32(numExitRoot)
436 idxBig := big.NewInt(idx)
437 return c.hermez.WithdrawMerkleProof(auth, tokenID, amount, babyPubKey, numExitRootB, siblings, idxBig, instantWithdraw)
438 },
439 ); err != nil {
440 return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawMerkleProof: %w", err))
441 }
442 return tx, nil
443}
444
445// RollupWithdrawCircuit is the interface to call the smart contract function
446func (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) {
447 log.Error("TODO")
448 return nil, tracerr.Wrap(errTODO)
449}
450
451// RollupL1UserTxERC20ETH is the interface to call the smart contract function
452func (c *RollupClient) RollupL1UserTxERC20ETH(fromBJJ babyjub.PublicKeyComp, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (tx *types.Transaction, err error) {
453 if tx, err = c.client.CallAuth(
454 0,
455 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
456 var babyPubKey *big.Int
457 if fromBJJ != common.EmptyBJJComp {
458 pkCompB := common.SwapEndianness(fromBJJ[:])
459 babyPubKey = new(big.Int).SetBytes(pkCompB)
460 } else {
461 babyPubKey = big.NewInt(0)
462 }
463 fromIdxBig := big.NewInt(fromIdx)
464 toIdxBig := big.NewInt(toIdx)
465 depositAmountF, err := common.NewFloat16(depositAmount)
466 if err != nil {
467 return nil, tracerr.Wrap(err)
468 }
469 amountF, err := common.NewFloat16(amount)
470 if err != nil {
471 return nil, tracerr.Wrap(err)
472 }
473 if tokenID == 0 {
474 auth.Value = depositAmount
475 }
476 var permit []byte
477 return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(depositAmountF),
478 uint16(amountF), tokenID, toIdxBig, permit)
479 },
480 ); err != nil {
481 return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20/ETH: %w", err))
482 }
483 return tx, nil
484}
485
486// RollupL1UserTxERC20Permit is the interface to call the smart contract function
487func (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) {
488 if tx, err = c.client.CallAuth(
489 0,
490 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
491 var babyPubKey *big.Int
492 if fromBJJ != common.EmptyBJJComp {
493 pkCompB := common.SwapEndianness(fromBJJ[:])
494 babyPubKey = new(big.Int).SetBytes(pkCompB)
495 } else {
496 babyPubKey = big.NewInt(0)
497 }
498 fromIdxBig := big.NewInt(fromIdx)
499 toIdxBig := big.NewInt(toIdx)
500 depositAmountF, err := common.NewFloat16(depositAmount)
501 if err != nil {
502 return nil, tracerr.Wrap(err)
503 }
504 amountF, err := common.NewFloat16(amount)
505 if err != nil {
506 return nil, tracerr.Wrap(err)
507 }
508 if tokenID == 0 {
509 auth.Value = depositAmount
510 }
511 owner := c.client.account.Address
512 spender := c.address
513 nonce, err := c.tokenHEZ.Nonces(c.opts, owner)
514 if err != nil {
515 return nil, tracerr.Wrap(err)
516 }
517 tokenName := c.tokenHEZCfg.Name
518 tokenAddr := c.tokenHEZCfg.Address
519 digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, amount, nonce, deadline, tokenName)
520 signature, _ := c.client.ks.SignHash(*c.client.account, digest)
521 permit := createPermit(owner, spender, amount, deadline, digest, signature)
522 return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(depositAmountF),
523 uint16(amountF), tokenID, toIdxBig, permit)
524 },
525 ); err != nil {
526 return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20Permit: %w", err))
527 }
528 return tx, nil
529}
530
531// RollupRegisterTokensCount is the interface to call the smart contract function
532func (c *RollupClient) RollupRegisterTokensCount() (registerTokensCount *big.Int, err error) {
533 if err := c.client.Call(func(ec *ethclient.Client) error {
534 registerTokensCount, err = c.hermez.RegisterTokensCount(c.opts)
535 return tracerr.Wrap(err)
536 }); err != nil {
537 return nil, tracerr.Wrap(err)
538 }
539 return registerTokensCount, nil
540}
541
542// RollupLastForgedBatch is the interface to call the smart contract function
543func (c *RollupClient) RollupLastForgedBatch() (lastForgedBatch int64, err error) {
544 if err := c.client.Call(func(ec *ethclient.Client) error {
545 _lastForgedBatch, err := c.hermez.LastForgedBatch(c.opts)
546 lastForgedBatch = int64(_lastForgedBatch)
547 return tracerr.Wrap(err)
548 }); err != nil {
549 return 0, tracerr.Wrap(err)
550 }
551 return lastForgedBatch, nil
552}
553
554// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
555func (c *RollupClient) RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (tx *types.Transaction, err error) {
556 if tx, err = c.client.CallAuth(
557 0,
558 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
559 return c.hermez.UpdateForgeL1L2BatchTimeout(auth, uint8(newForgeL1L2BatchTimeout))
560 },
561 ); err != nil {
562 return nil, tracerr.Wrap(fmt.Errorf("Failed update ForgeL1L2BatchTimeout: %w", err))
563 }
564 return tx, nil
565}
566
567// RollupUpdateFeeAddToken is the interface to call the smart contract function
568func (c *RollupClient) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
569 if tx, err = c.client.CallAuth(
570 0,
571 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
572 return c.hermez.UpdateFeeAddToken(auth, newFeeAddToken)
573 },
574 ); err != nil {
575 return nil, tracerr.Wrap(fmt.Errorf("Failed update FeeAddToken: %w", err))
576 }
577 return tx, nil
578}
579
580// RollupUpdateBucketsParameters is the interface to call the smart contract function
581func (c *RollupClient) RollupUpdateBucketsParameters(
582 arrayBuckets [common.RollupConstNumBuckets]RollupUpdateBucketsParameters,
583) (tx *types.Transaction, err error) {
584 params := [common.RollupConstNumBuckets][4]*big.Int{}
585 for i, bucket := range arrayBuckets {
586 params[i][0] = bucket.CeilUSD
587 params[i][1] = bucket.Withdrawals
588 params[i][2] = bucket.BlockWithdrawalRate
589 params[i][3] = bucket.MaxWithdrawals
590 }
591 if tx, err = c.client.CallAuth(
592 12500000, //nolint:gomnd
593 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
594 return c.hermez.UpdateBucketsParameters(auth, params)
595 },
596 ); err != nil {
597 return nil, tracerr.Wrap(fmt.Errorf("Failed update Buckets Parameters: %w", err))
598 }
599 return tx, nil
600}
601
602// RollupUpdateTokenExchange is the interface to call the smart contract function
603func (c *RollupClient) RollupUpdateTokenExchange(addressArray []ethCommon.Address, valueArray []uint64) (tx *types.Transaction, err error) {
604 if tx, err = c.client.CallAuth(
605 0,
606 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
607 return c.hermez.UpdateTokenExchange(auth, addressArray, valueArray)
608 },
609 ); err != nil {
610 return nil, tracerr.Wrap(fmt.Errorf("Failed update Token Exchange: %w", err))
611 }
612 return tx, nil
613}
614
615// RollupUpdateWithdrawalDelay is the interface to call the smart contract function
616func (c *RollupClient) RollupUpdateWithdrawalDelay(newWithdrawalDelay int64) (tx *types.Transaction, err error) {
617 if tx, err = c.client.CallAuth(
618 0,
619 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
620 return c.hermez.UpdateWithdrawalDelay(auth, uint64(newWithdrawalDelay))
621 },
622 ); err != nil {
623 return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawalDelay: %w", err))
624 }
625 return tx, nil
626}
627
628// RollupSafeMode is the interface to call the smart contract function
629func (c *RollupClient) RollupSafeMode() (tx *types.Transaction, err error) {
630 if tx, err = c.client.CallAuth(
631 0,
632 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
633 return c.hermez.SafeMode(auth)
634 },
635 ); err != nil {
636 return nil, tracerr.Wrap(fmt.Errorf("Failed update Safe Mode: %w", err))
637 }
638 return tx, nil
639}
640
641// RollupInstantWithdrawalViewer is the interface to call the smart contract function
642func (c *RollupClient) RollupInstantWithdrawalViewer(tokenAddress ethCommon.Address, amount *big.Int) (instantAllowed bool, err error) {
643 if err := c.client.Call(func(ec *ethclient.Client) error {
644 instantAllowed, err = c.hermez.InstantWithdrawalViewer(c.opts, tokenAddress, amount)
645 return tracerr.Wrap(err)
646 }); err != nil {
647 return false, tracerr.Wrap(err)
648 }
649 return instantAllowed, nil
650}
651
652// RollupConstants returns the Constants of the Rollup Smart Contract
653func (c *RollupClient) RollupConstants() (rollupConstants *common.RollupConstants, err error) {
654 rollupConstants = new(common.RollupConstants)
655 if err := c.client.Call(func(ec *ethclient.Client) error {
656 absoluteMaxL1L2BatchTimeout, err := c.hermez.ABSOLUTEMAXL1L2BATCHTIMEOUT(c.opts)
657 if err != nil {
658 return tracerr.Wrap(err)
659 }
660 rollupConstants.AbsoluteMaxL1L2BatchTimeout = int64(absoluteMaxL1L2BatchTimeout)
661 rollupConstants.TokenHEZ, err = c.hermez.TokenHEZ(c.opts)
662 if err != nil {
663 return tracerr.Wrap(err)
664 }
665 for i := int64(0); i < int64(common.LenVerifiers); i++ {
666 var newRollupVerifier common.RollupVerifierStruct
667 rollupVerifier, err := c.hermez.RollupVerifiers(c.opts, big.NewInt(i))
668 if err != nil {
669 return tracerr.Wrap(err)
670 }
671 newRollupVerifier.MaxTx = rollupVerifier.MaxTx.Int64()
672 newRollupVerifier.NLevels = rollupVerifier.NLevels.Int64()
673 rollupConstants.Verifiers = append(rollupConstants.Verifiers, newRollupVerifier)
674 }
675 rollupConstants.HermezAuctionContract, err = c.hermez.HermezAuctionContract(c.opts)
676 if err != nil {
677 return tracerr.Wrap(err)
678 }
679 rollupConstants.HermezGovernanceAddress, err = c.hermez.HermezGovernanceAddress(c.opts)
680 if err != nil {
681 return tracerr.Wrap(err)
682 }
683 rollupConstants.WithdrawDelayerContract, err = c.hermez.WithdrawDelayerContract(c.opts)
684 return tracerr.Wrap(err)
685 }); err != nil {
686 return nil, tracerr.Wrap(err)
687 }
688 return rollupConstants, nil
689}
690
691var (
692 logHermezL1UserTxEvent = crypto.Keccak256Hash([]byte("L1UserTxEvent(uint32,uint8,bytes)"))
693 logHermezAddToken = crypto.Keccak256Hash([]byte("AddToken(address,uint32)"))
694 logHermezForgeBatch = crypto.Keccak256Hash([]byte("ForgeBatch(uint32,uint16)"))
695 logHermezUpdateForgeL1L2BatchTimeout = crypto.Keccak256Hash([]byte("UpdateForgeL1L2BatchTimeout(uint8)"))
696 logHermezUpdateFeeAddToken = crypto.Keccak256Hash([]byte("UpdateFeeAddToken(uint256)"))
697 logHermezWithdrawEvent = crypto.Keccak256Hash([]byte("WithdrawEvent(uint48,uint32,bool)"))
698 logHermezUpdateBucketWithdraw = crypto.Keccak256Hash([]byte("UpdateBucketWithdraw(uint8,uint256,uint256)"))
699 logHermezUpdateWithdrawalDelay = crypto.Keccak256Hash([]byte("UpdateWithdrawalDelay(uint64)"))
700 logHermezUpdateBucketsParameters = crypto.Keccak256Hash([]byte("UpdateBucketsParameters(uint256[4][" +
701 strconv.Itoa(common.RollupConstNumBuckets) + "])"))
702 logHermezUpdateTokenExchange = crypto.Keccak256Hash([]byte("UpdateTokenExchange(address[],uint64[])"))
703 logHermezSafeMode = crypto.Keccak256Hash([]byte("SafeMode()"))
704 logHermezInitialize = crypto.Keccak256Hash([]byte("InitializeHermezEvent(uint8,uint256,uint64)"))
705)
706
707// RollupEventInit returns the initialize event with its corresponding block number
708func (c *RollupClient) RollupEventInit() (*RollupEventInitialize, int64, error) {
709 query := ethereum.FilterQuery{
710 Addresses: []ethCommon.Address{
711 c.address,
712 },
713 Topics: [][]ethCommon.Hash{{logHermezInitialize}},
714 }
715 logs, err := c.client.client.FilterLogs(context.Background(), query)
716 if err != nil {
717 return nil, 0, tracerr.Wrap(err)
718 }
719 if len(logs) != 1 {
720 return nil, 0, tracerr.Wrap(fmt.Errorf("no event of type InitializeHermezEvent found"))
721 }
722 vLog := logs[0]
723 if vLog.Topics[0] != logHermezInitialize {
724 return nil, 0, tracerr.Wrap(fmt.Errorf("event is not InitializeHermezEvent"))
725 }
726
727 var rollupInit RollupEventInitialize
728 if err := c.contractAbi.UnpackIntoInterface(&rollupInit, "InitializeHermezEvent", vLog.Data); err != nil {
729 return nil, 0, tracerr.Wrap(err)
730 }
731 return &rollupInit, int64(vLog.BlockNumber), tracerr.Wrap(err)
732}
733
734// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
735func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) {
736 var rollupEvents RollupEvents
737 var blockHash *ethCommon.Hash
738
739 query := ethereum.FilterQuery{
740 FromBlock: big.NewInt(blockNum),
741 ToBlock: big.NewInt(blockNum),
742 Addresses: []ethCommon.Address{
743 c.address,
744 },
745 BlockHash: nil,
746 Topics: [][]ethCommon.Hash{},
747 }
748 logs, err := c.client.client.FilterLogs(context.Background(), query)
749 if err != nil {
750 return nil, nil, tracerr.Wrap(err)
751 }
752 if len(logs) > 0 {
753 blockHash = &logs[0].BlockHash
754 }
755 for _, vLog := range logs {
756 if vLog.BlockHash != *blockHash {
757 log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String())
758 return nil, nil, tracerr.Wrap(ErrBlockHashMismatchEvent)
759 }
760 switch vLog.Topics[0] {
761 case logHermezL1UserTxEvent:
762 var L1UserTxAux rollupEventL1UserTxAux
763 var L1UserTx RollupEventL1UserTx
764 err := c.contractAbi.UnpackIntoInterface(&L1UserTxAux, "L1UserTxEvent", vLog.Data)
765 if err != nil {
766 return nil, nil, tracerr.Wrap(err)
767 }
768 L1Tx, err := common.L1UserTxFromBytes(L1UserTxAux.L1UserTx)
769 if err != nil {
770 return nil, nil, tracerr.Wrap(err)
771 }
772 toForgeL1TxsNum := new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
773 L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
774 L1Tx.Position = int(new(big.Int).SetBytes(vLog.Topics[2][:]).Int64())
775 L1Tx.UserOrigin = true
776 L1UserTx.L1UserTx = *L1Tx
777 rollupEvents.L1UserTx = append(rollupEvents.L1UserTx, L1UserTx)
778 case logHermezAddToken:
779 var addToken RollupEventAddToken
780 err := c.contractAbi.UnpackIntoInterface(&addToken, "AddToken", vLog.Data)
781 if err != nil {
782 return nil, nil, tracerr.Wrap(err)
783 }
784 addToken.TokenAddress = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
785 rollupEvents.AddToken = append(rollupEvents.AddToken, addToken)
786 case logHermezForgeBatch:
787 var forgeBatch RollupEventForgeBatch
788 err := c.contractAbi.UnpackIntoInterface(&forgeBatch, "ForgeBatch", vLog.Data)
789 if err != nil {
790 return nil, nil, tracerr.Wrap(err)
791 }
792 forgeBatch.BatchNum = new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
793 forgeBatch.EthTxHash = vLog.TxHash
794 // forgeBatch.Sender = vLog.Address
795 rollupEvents.ForgeBatch = append(rollupEvents.ForgeBatch, forgeBatch)
796 case logHermezUpdateForgeL1L2BatchTimeout:
797 var updateForgeL1L2BatchTimeout struct {
798 NewForgeL1L2BatchTimeout uint8
799 }
800 err := c.contractAbi.UnpackIntoInterface(&updateForgeL1L2BatchTimeout, "UpdateForgeL1L2BatchTimeout", vLog.Data)
801 if err != nil {
802 return nil, nil, tracerr.Wrap(err)
803 }
804 rollupEvents.UpdateForgeL1L2BatchTimeout = append(rollupEvents.UpdateForgeL1L2BatchTimeout,
805 RollupEventUpdateForgeL1L2BatchTimeout{
806 NewForgeL1L2BatchTimeout: int64(updateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout),
807 })
808 case logHermezUpdateFeeAddToken:
809 var updateFeeAddToken RollupEventUpdateFeeAddToken
810 err := c.contractAbi.UnpackIntoInterface(&updateFeeAddToken, "UpdateFeeAddToken", vLog.Data)
811 if err != nil {
812 return nil, nil, tracerr.Wrap(err)
813 }
814 rollupEvents.UpdateFeeAddToken = append(rollupEvents.UpdateFeeAddToken, updateFeeAddToken)
815 case logHermezWithdrawEvent:
816 var withdraw RollupEventWithdraw
817 withdraw.Idx = new(big.Int).SetBytes(vLog.Topics[1][:]).Uint64()
818 withdraw.NumExitRoot = new(big.Int).SetBytes(vLog.Topics[2][:]).Uint64()
819 instantWithdraw := new(big.Int).SetBytes(vLog.Topics[3][:]).Uint64()
820 if instantWithdraw == 1 {
821 withdraw.InstantWithdraw = true
822 }
823 withdraw.TxHash = vLog.TxHash
824 rollupEvents.Withdraw = append(rollupEvents.Withdraw, withdraw)
825 case logHermezUpdateBucketWithdraw:
826 var updateBucketWithdrawAux rollupEventUpdateBucketWithdrawAux
827 var updateBucketWithdraw RollupEventUpdateBucketWithdraw
828 err := c.contractAbi.UnpackIntoInterface(&updateBucketWithdrawAux, "UpdateBucketWithdraw", vLog.Data)
829 if err != nil {
830 return nil, nil, tracerr.Wrap(err)
831 }
832 updateBucketWithdraw.Withdrawals = updateBucketWithdrawAux.Withdrawals
833 updateBucketWithdraw.NumBucket = int(new(big.Int).SetBytes(vLog.Topics[1][:]).Int64())
834 updateBucketWithdraw.BlockStamp = new(big.Int).SetBytes(vLog.Topics[2][:]).Int64()
835 rollupEvents.UpdateBucketWithdraw = append(rollupEvents.UpdateBucketWithdraw, updateBucketWithdraw)
836
837 case logHermezUpdateWithdrawalDelay:
838 var withdrawalDelay RollupEventUpdateWithdrawalDelay
839 err := c.contractAbi.UnpackIntoInterface(&withdrawalDelay, "UpdateWithdrawalDelay", vLog.Data)
840 if err != nil {
841 return nil, nil, tracerr.Wrap(err)
842 }
843 rollupEvents.UpdateWithdrawalDelay = append(rollupEvents.UpdateWithdrawalDelay, withdrawalDelay)
844 case logHermezUpdateBucketsParameters:
845 var bucketsParametersAux rollupEventUpdateBucketsParametersAux
846 var bucketsParameters RollupEventUpdateBucketsParameters
847 err := c.contractAbi.UnpackIntoInterface(&bucketsParametersAux, "UpdateBucketsParameters", vLog.Data)
848 if err != nil {
849 return nil, nil, tracerr.Wrap(err)
850 }
851 for i, bucket := range bucketsParametersAux.ArrayBuckets {
852 bucketsParameters.ArrayBuckets[i].CeilUSD = bucket[0]
853 bucketsParameters.ArrayBuckets[i].Withdrawals = bucket[1]
854 bucketsParameters.ArrayBuckets[i].BlockWithdrawalRate = bucket[2]
855 bucketsParameters.ArrayBuckets[i].MaxWithdrawals = bucket[3]
856 }
857 rollupEvents.UpdateBucketsParameters = append(rollupEvents.UpdateBucketsParameters, bucketsParameters)
858 case logHermezUpdateTokenExchange:
859 var tokensExchange RollupEventUpdateTokenExchange
860 err := c.contractAbi.UnpackIntoInterface(&tokensExchange, "UpdateTokenExchange", vLog.Data)
861 if err != nil {
862 return nil, nil, tracerr.Wrap(err)
863 }
864 rollupEvents.UpdateTokenExchange = append(rollupEvents.UpdateTokenExchange, tokensExchange)
865 case logHermezSafeMode:
866 var safeMode RollupEventSafeMode
867 rollupEvents.SafeMode = append(rollupEvents.SafeMode, safeMode)
868 // Also add an UpdateBucketsParameter with
869 // SafeMode=true to keep the order between `safeMode`
870 // and `UpdateBucketsParameters`
871 bucketsParameters := RollupEventUpdateBucketsParameters{
872 SafeMode: true,
873 }
874 for i := range bucketsParameters.ArrayBuckets {
875 bucketsParameters.ArrayBuckets[i].CeilUSD = big.NewInt(0)
876 bucketsParameters.ArrayBuckets[i].Withdrawals = big.NewInt(0)
877 bucketsParameters.ArrayBuckets[i].BlockWithdrawalRate = big.NewInt(0)
878 bucketsParameters.ArrayBuckets[i].MaxWithdrawals = big.NewInt(0)
879 }
880 rollupEvents.UpdateBucketsParameters = append(rollupEvents.UpdateBucketsParameters,
881 bucketsParameters)
882 }
883 }
884 return &rollupEvents, blockHash, nil
885}
886
887// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the
888// Rollup Smart Contract in the given transaction, and the sender address.
889func (c *RollupClient) RollupForgeBatchArgs(ethTxHash ethCommon.Hash, l1UserTxsLen uint16) (*RollupForgeBatchArgs, *ethCommon.Address, error) {
890 tx, _, err := c.client.client.TransactionByHash(context.Background(), ethTxHash)
891 if err != nil {
892 return nil, nil, tracerr.Wrap(err)
893 }
894 txData := tx.Data()
895
896 method, err := c.contractAbi.MethodById(txData[:4])
897 if err != nil {
898 return nil, nil, tracerr.Wrap(err)
899 }
900 receipt, err := c.client.client.TransactionReceipt(context.Background(), ethTxHash)
901 if err != nil {
902 return nil, nil, tracerr.Wrap(err)
903 }
904 sender, err := c.client.client.TransactionSender(context.Background(), tx, receipt.Logs[0].BlockHash, receipt.Logs[0].Index)
905 if err != nil {
906 return nil, nil, tracerr.Wrap(err)
907 }
908 var aux rollupForgeBatchArgsAux
909 if values, err := method.Inputs.Unpack(txData[4:]); err != nil {
910 return nil, nil, tracerr.Wrap(err)
911 } else if err := method.Inputs.Copy(&aux, values); err != nil {
912 return nil, nil, tracerr.Wrap(err)
913 }
914 rollupForgeBatchArgs := RollupForgeBatchArgs{
915 L1Batch: aux.L1Batch,
916 NewExitRoot: aux.NewExitRoot,
917 NewLastIdx: aux.NewLastIdx.Int64(),
918 NewStRoot: aux.NewStRoot,
919 ProofA: aux.ProofA,
920 ProofB: aux.ProofB,
921 ProofC: aux.ProofC,
922 VerifierIdx: aux.VerifierIdx,
923 L1CoordinatorTxs: []common.L1Tx{},
924 L1CoordinatorTxsAuths: [][]byte{},
925 L2TxsData: []common.L2Tx{},
926 FeeIdxCoordinator: []common.Idx{},
927 }
928 nLevels := c.consts.Verifiers[rollupForgeBatchArgs.VerifierIdx].NLevels
929 lenL1L2TxsBytes := int((nLevels/8)*2 + 2 + 1)
930 numBytesL1TxUser := int(l1UserTxsLen) * lenL1L2TxsBytes
931 numTxsL1Coord := len(aux.EncodedL1CoordinatorTx) / common.L1CoordinatorTxBytesLen
932 numBytesL1TxCoord := numTxsL1Coord * lenL1L2TxsBytes
933 numBeginL2Tx := numBytesL1TxCoord + numBytesL1TxUser
934 l1UserTxsData := []byte{}
935 if l1UserTxsLen > 0 {
936 l1UserTxsData = aux.L1L2TxsData[:numBytesL1TxUser]
937 }
938 for i := 0; i < int(l1UserTxsLen); i++ {
939 l1Tx, err := common.L1TxFromDataAvailability(l1UserTxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], uint32(nLevels))
940 if err != nil {
941 return nil, nil, tracerr.Wrap(err)
942 }
943 rollupForgeBatchArgs.L1UserTxs = append(rollupForgeBatchArgs.L1UserTxs, *l1Tx)
944 }
945 l2TxsData := []byte{}
946 if numBeginL2Tx < len(aux.L1L2TxsData) {
947 l2TxsData = aux.L1L2TxsData[numBeginL2Tx:]
948 }
949 numTxsL2 := len(l2TxsData) / lenL1L2TxsBytes
950 for i := 0; i < numTxsL2; i++ {
951 l2Tx, err := common.L2TxFromBytesDataAvailability(l2TxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], int(nLevels))
952 if err != nil {
953 return nil, nil, tracerr.Wrap(err)
954 }
955 rollupForgeBatchArgs.L2TxsData = append(rollupForgeBatchArgs.L2TxsData, *l2Tx)
956 }
957 for i := 0; i < numTxsL1Coord; i++ {
958 bytesL1Coordinator := aux.EncodedL1CoordinatorTx[i*common.L1CoordinatorTxBytesLen : (i+1)*common.L1CoordinatorTxBytesLen]
959 var signature []byte
960 v := bytesL1Coordinator[0]
961 s := bytesL1Coordinator[1:33]
962 r := bytesL1Coordinator[33:65]
963 signature = append(signature, r[:]...)
964 signature = append(signature, s[:]...)
965 signature = append(signature, v)
966 l1Tx, err := common.L1CoordinatorTxFromBytes(bytesL1Coordinator, c.chainID, c.address)
967 if err != nil {
968 return nil, nil, tracerr.Wrap(err)
969 }
970 rollupForgeBatchArgs.L1CoordinatorTxs = append(rollupForgeBatchArgs.L1CoordinatorTxs, *l1Tx)
971 rollupForgeBatchArgs.L1CoordinatorTxsAuths = append(rollupForgeBatchArgs.L1CoordinatorTxsAuths, signature)
972 }
973 lenFeeIdxCoordinatorBytes := int(nLevels / 8) //nolint:gomnd
974 numFeeIdxCoordinator := len(aux.FeeIdxCoordinator) / lenFeeIdxCoordinatorBytes
975 for i := 0; i < numFeeIdxCoordinator; i++ {
976 var paddedFeeIdx [6]byte
977 // TODO: This check is not necessary: the first case will always work. Test it before removing the if.
978 if lenFeeIdxCoordinatorBytes < common.IdxBytesLen {
979 copy(paddedFeeIdx[6-lenFeeIdxCoordinatorBytes:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
980 } else {
981 copy(paddedFeeIdx[:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
982 }
983 feeIdxCoordinator, err := common.IdxFromBytes(paddedFeeIdx[:])
984 if err != nil {
985 return nil, nil, tracerr.Wrap(err)
986 }
987 if feeIdxCoordinator != common.Idx(0) {
988 rollupForgeBatchArgs.FeeIdxCoordinator = append(rollupForgeBatchArgs.FeeIdxCoordinator, feeIdxCoordinator)
989 }
990 }
991 return &rollupForgeBatchArgs, &sender, nil
992}