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