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