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