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}