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