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