arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/eth/rollup.go
eth/rollup.goRaw
  1package eth
  2
  3import (
  4	"context"
  5	"fmt"
  6	"math/big"
  7	"strings"
  8
  9	"github.com/ethereum/go-ethereum"
 10	"github.com/ethereum/go-ethereum/accounts/abi"
 11	"github.com/ethereum/go-ethereum/accounts/abi/bind"
 12	ethCommon "github.com/ethereum/go-ethereum/common"
 13	"github.com/ethereum/go-ethereum/core/types"
 14	"github.com/ethereum/go-ethereum/crypto"
 15	"github.com/ethereum/go-ethereum/ethclient"
 16	"github.com/hermeznetwork/hermez-node/common"
 17	ERC777 "github.com/hermeznetwork/hermez-node/eth/contracts/erc777"
 18	Hermez "github.com/hermeznetwork/hermez-node/eth/contracts/hermez"
 19	"github.com/hermeznetwork/hermez-node/log"
 20	"github.com/iden3/go-iden3-crypto/babyjub"
 21	"golang.org/x/crypto/sha3"
 22)
 23
 24const (
 25	// RollupConstMaxFeeIdxCoordinator is the maximum number of tokens the
 26	// coordinator can use to collect fees (determines the number of tokens
 27	// that the coordinator can collect fees from).  This value is
 28	// determined by the circuit.
 29	RollupConstMaxFeeIdxCoordinator = 64
 30	// RollupConstReservedIDx First 256 indexes reserved, first user index will be the 256
 31	RollupConstReservedIDx = 255
 32	// RollupConstExitIDx IDX 1 is reserved for exits
 33	RollupConstExitIDx = 1
 34	// RollupConstLimitLoadAmount Max load amount allowed (loadAmount: L1 --> L2)
 35	RollupConstLimitLoadAmount = (1 << 128)
 36	// RollupConstLimitL2TransferAmount Max amount allowed (amount L2 --> L2)
 37	RollupConstLimitL2TransferAmount = (1 << 192)
 38	// RollupConstLimitTokens Max number of tokens allowed to be registered inside the rollup
 39	RollupConstLimitTokens = (1 << 32)
 40	// RollupConstL1CoordinatorTotalBytes [4 bytes] token + [32 bytes] babyjub + [65 bytes] compressedSignature
 41	RollupConstL1CoordinatorTotalBytes = 101
 42	// RollupConstL1UserTotalBytes [20 bytes] fromEthAddr + [32 bytes] fromBjj-compressed + [6 bytes] fromIdx +
 43	// [2 bytes] loadAmountFloat16 + [2 bytes] amountFloat16 + [4 bytes] tokenId + [6 bytes] toIdx
 44	RollupConstL1UserTotalBytes = 72
 45	// RollupConstMaxL1UserTx Maximum L1-user transactions allowed to be queued in a batch
 46	RollupConstMaxL1UserTx = 128
 47	// RollupConstMaxL1Tx Maximum L1 transactions allowed to be queued in a batch
 48	RollupConstMaxL1Tx = 256
 49	// RollupConstInputSHAConstantBytes [6 bytes] lastIdx + [6 bytes] newLastIdx  + [32 bytes] stateRoot  + [32 bytes] newStRoot  + [32 bytes] newExitRoot +
 50	// [_MAX_L1_TX * _L1_USER_TOTALBYTES bytes] l1TxsData + totalL2TxsDataLength + feeIdxCoordinatorLength + [2 bytes] chainID =
 51	// 18542 bytes +  totalL2TxsDataLength + feeIdxCoordinatorLength
 52	RollupConstInputSHAConstantBytes = 18542
 53	// RollupConstNumBuckets Number of buckets
 54	RollupConstNumBuckets = 5
 55	// RollupConstMaxWithdrawalDelay max withdrawal delay in seconds
 56	RollupConstMaxWithdrawalDelay = 2 * 7 * 24 * 60 * 60
 57	// RollupConstExchangeMultiplier exchange multiplier
 58	RollupConstExchangeMultiplier = 1e14
 59	// LenVerifiers number of Rollup Smart Contract Verifiers
 60	LenVerifiers = 1
 61)
 62
 63var (
 64	// RollupConstEthAddressInternalOnly This ethereum address is used internally for rollup accounts that don't have ethereum address, only Babyjubjub
 65	// This non-ethereum accounts can be created by the coordinator and allow users to have a rollup
 66	// account without needing an ethereum address
 67	RollupConstEthAddressInternalOnly = ethCommon.HexToAddress("0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF")
 68	// RollupConstRfield Modulus zkSNARK
 69	RollupConstRfield, _ = new(big.Int).SetString(
 70		"21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
 71
 72	// RollupConstERC1820 ERC1820Registry address
 73	RollupConstERC1820 = ethCommon.HexToAddress("0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24")
 74
 75	// ERC777 tokens signatures
 76
 77	// RollupConstRecipientInterfaceHash ERC777 recipient interface hash
 78	RollupConstRecipientInterfaceHash = crypto.Keccak256([]byte("ERC777TokensRecipient"))
 79	// RollupConstPerformL1UserTxSignature the signature of the function that can be called thru an ERC777 `send`
 80	RollupConstPerformL1UserTxSignature = crypto.Keccak256([]byte("addL1Transaction(uint256,uint48,uint16,uint16,uint32,uint48)"))
 81	// RollupConstAddTokenSignature the signature of the function that can be called thru an ERC777 `send`
 82	RollupConstAddTokenSignature = crypto.Keccak256([]byte("addToken(address)"))
 83	// RollupConstSendSignature ERC777 Signature
 84	RollupConstSendSignature = crypto.Keccak256([]byte("send(address,uint256,bytes)"))
 85	// RollupConstERC777Granularity ERC777 Signature
 86	RollupConstERC777Granularity = crypto.Keccak256([]byte("granularity()"))
 87	// RollupConstWithdrawalDelayerDeposit  This constant are used to deposit tokens from ERC77 tokens into withdrawal delayer
 88	RollupConstWithdrawalDelayerDeposit = crypto.Keccak256([]byte("deposit(address,address,uint192)"))
 89
 90	// ERC20 signature
 91
 92	// RollupConstTransferSignature This constant is used in the _safeTransfer internal method in order to safe GAS.
 93	RollupConstTransferSignature = crypto.Keccak256([]byte("transfer(address,uint256)"))
 94	// RollupConstTransferFromSignature This constant is used in the _safeTransfer internal method in order to safe GAS.
 95	RollupConstTransferFromSignature = crypto.Keccak256([]byte("transferFrom(address,address,uint256)"))
 96	// RollupConstApproveSignature This constant is used in the _safeTransfer internal method in order to safe GAS.
 97	RollupConstApproveSignature = crypto.Keccak256([]byte("approve(address,uint256)"))
 98	// RollupConstERC20Signature ERC20 decimals signature
 99	RollupConstERC20Signature = crypto.Keccak256([]byte("decimals()"))
100)
101
102// RollupPublicConstants are the constants of the Rollup Smart Contract
103type RollupPublicConstants struct {
104	AbsoluteMaxL1L2BatchTimeout int64
105	TokenHEZ                    ethCommon.Address
106	Verifiers                   []RollupVerifierStruct
107	HermezAuctionContract       ethCommon.Address
108	HermezGovernanceDAOAddress  ethCommon.Address
109	SafetyAddress               ethCommon.Address
110	WithdrawDelayerContract     ethCommon.Address
111}
112
113// RollupVariables are the variables of the Rollup Smart Contract
114type RollupVariables struct {
115	FeeAddToken           *big.Int
116	ForgeL1L2BatchTimeout int64
117	WithdrawalDelay       uint64
118}
119
120// QueueStruct is the queue of L1Txs for a batch
121type QueueStruct struct {
122	L1TxQueue    []common.L1Tx
123	TotalL1TxFee *big.Int
124}
125
126// NewQueueStruct creates a new clear QueueStruct.
127func NewQueueStruct() *QueueStruct {
128	return &QueueStruct{
129		L1TxQueue:    make([]common.L1Tx, 0),
130		TotalL1TxFee: big.NewInt(0),
131	}
132}
133
134// RollupVerifierStruct is the information about verifiers of the Rollup Smart Contract
135type RollupVerifierStruct struct {
136	MaxTx   int64
137	NLevels int64
138}
139
140// RollupState represents the state of the Rollup in the Smart Contract
141type RollupState struct {
142	StateRoot              *big.Int
143	ExitRoots              []*big.Int
144	ExitNullifierMap       map[[256 / 8]byte]bool
145	TokenList              []ethCommon.Address
146	TokenMap               map[ethCommon.Address]bool
147	MapL1TxQueue           map[int64]*QueueStruct
148	LastL1L2Batch          int64
149	CurrentToForgeL1TxsNum int64
150	LastToForgeL1TxsNum    int64
151	CurrentIdx             int64
152}
153
154// RollupEventL1UserTx is an event of the Rollup Smart Contract
155type RollupEventL1UserTx struct {
156	// ToForgeL1TxsNum int64 // QueueIndex       *big.Int
157	// Position        int   // TransactionIndex *big.Int
158	L1UserTx common.L1Tx
159}
160
161// RollupEventL1UserTxAux is an event of the Rollup Smart Contract
162type RollupEventL1UserTxAux struct {
163	ToForgeL1TxsNum uint64 // QueueIndex       *big.Int
164	Position        uint8  // TransactionIndex *big.Int
165	L1UserTx        []byte
166}
167
168// RollupEventAddToken is an event of the Rollup Smart Contract
169type RollupEventAddToken struct {
170	TokenAddress ethCommon.Address
171	TokenID      uint32
172}
173
174// RollupEventForgeBatch is an event of the Rollup Smart Contract
175type RollupEventForgeBatch struct {
176	BatchNum int64
177	// Sender    ethCommon.Address
178	EthTxHash ethCommon.Hash
179}
180
181// RollupEventUpdateForgeL1L2BatchTimeout is an event of the Rollup Smart Contract
182type RollupEventUpdateForgeL1L2BatchTimeout struct {
183	NewForgeL1L2BatchTimeout int64
184}
185
186// RollupEventUpdateFeeAddToken is an event of the Rollup Smart Contract
187type RollupEventUpdateFeeAddToken struct {
188	NewFeeAddToken *big.Int
189}
190
191// RollupEventWithdrawEvent is an event of the Rollup Smart Contract
192type RollupEventWithdrawEvent struct {
193	Idx             uint64
194	NumExitRoot     uint64
195	InstantWithdraw bool
196}
197
198// RollupEvents is the list of events in a block of the Rollup Smart Contract
199type RollupEvents struct {
200	L1UserTx                    []RollupEventL1UserTx
201	AddToken                    []RollupEventAddToken
202	ForgeBatch                  []RollupEventForgeBatch
203	UpdateForgeL1L2BatchTimeout []RollupEventUpdateForgeL1L2BatchTimeout
204	UpdateFeeAddToken           []RollupEventUpdateFeeAddToken
205	WithdrawEvent               []RollupEventWithdrawEvent
206}
207
208// NewRollupEvents creates an empty RollupEvents with the slices initialized.
209func NewRollupEvents() RollupEvents {
210	return RollupEvents{
211		L1UserTx:                    make([]RollupEventL1UserTx, 0),
212		AddToken:                    make([]RollupEventAddToken, 0),
213		ForgeBatch:                  make([]RollupEventForgeBatch, 0),
214		UpdateForgeL1L2BatchTimeout: make([]RollupEventUpdateForgeL1L2BatchTimeout, 0),
215		UpdateFeeAddToken:           make([]RollupEventUpdateFeeAddToken, 0),
216		WithdrawEvent:               make([]RollupEventWithdrawEvent, 0),
217	}
218}
219
220// RollupForgeBatchArgs are the arguments to the ForgeBatch function in the Rollup Smart Contract
221type RollupForgeBatchArgs struct {
222	NewLastIdx            int64
223	NewStRoot             *big.Int
224	NewExitRoot           *big.Int
225	L1CoordinatorTxs      []common.L1Tx
226	L1CoordinatorTxsAuths [][]byte // Authorization for accountCreations for each L1CoordinatorTx
227	L2TxsData             []common.L2Tx
228	FeeIdxCoordinator     []common.Idx
229	// Circuit selector
230	VerifierIdx uint8
231	L1Batch     bool
232	ProofA      [2]*big.Int
233	ProofB      [2][2]*big.Int
234	ProofC      [2]*big.Int
235}
236
237// RollupForgeBatchArgsAux are the arguments to the ForgeBatch function in the Rollup Smart Contract
238type RollupForgeBatchArgsAux struct {
239	NewLastIdx             *big.Int
240	NewStRoot              *big.Int
241	NewExitRoot            *big.Int
242	EncodedL1CoordinatorTx []byte
243	L2TxsData              []byte
244	FeeIdxCoordinator      []byte
245	// Circuit selector
246	VerifierIdx uint8
247	L1Batch     bool
248	ProofA      [2]*big.Int
249	ProofB      [2][2]*big.Int
250	ProofC      [2]*big.Int
251}
252
253// RollupInterface is the inteface to to Rollup Smart Contract
254type RollupInterface interface {
255	//
256	// Smart Contract Methods
257	//
258
259	// Public Functions
260
261	RollupForgeBatch(*RollupForgeBatchArgs) (*types.Transaction, error)
262	RollupAddToken(tokenAddress ethCommon.Address, feeAddToken *big.Int) (*types.Transaction, error)
263
264	RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error)
265	RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error)
266
267	RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error)
268	RollupL1UserTxERC777(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error)
269
270	// Governance Public Functions
271	RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (*types.Transaction, error)
272	RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (*types.Transaction, error)
273
274	// Viewers
275	RollupRegisterTokensCount() (*big.Int, error)
276
277	//
278	// Smart Contract Status
279	//
280
281	RollupConstants() (*RollupPublicConstants, error)
282	RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error)
283	RollupForgeBatchArgs(ethCommon.Hash) (*RollupForgeBatchArgs, *ethCommon.Address, error)
284}
285
286//
287// Implementation
288//
289
290// RollupClient is the implementation of the interface to the Rollup Smart Contract in ethereum.
291type RollupClient struct {
292	client          *EthereumClient
293	address         ethCommon.Address
294	tokenHEZAddress ethCommon.Address
295	hermez          *Hermez.Hermez
296	contractAbi     abi.ABI
297}
298
299// NewRollupClient creates a new RollupClient
300func NewRollupClient(client *EthereumClient, address ethCommon.Address, tokenHEZAddress ethCommon.Address) (*RollupClient, error) {
301	contractAbi, err := abi.JSON(strings.NewReader(string(Hermez.HermezABI)))
302	if err != nil {
303		return nil, err
304	}
305	hermez, err := Hermez.NewHermez(address, client.Client())
306	if err != nil {
307		return nil, err
308	}
309	return &RollupClient{
310		client:          client,
311		address:         address,
312		tokenHEZAddress: tokenHEZAddress,
313		hermez:          hermez,
314		contractAbi:     contractAbi,
315	}, nil
316}
317
318// RollupForgeBatch is the interface to call the smart contract function
319func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (tx *types.Transaction, err error) {
320	if tx, err = c.client.CallAuth(
321		1000000, //nolint:gomnd
322		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
323			rollupConst, err := c.RollupConstants()
324			if err != nil {
325				return nil, err
326			}
327			nLevels := rollupConst.Verifiers[args.VerifierIdx].NLevels
328			lenBytes := nLevels / 8 //nolint:gomnd
329			newLastIdx := big.NewInt(int64(args.NewLastIdx))
330			var l1CoordinatorBytes []byte
331			for i := 0; i < len(args.L1CoordinatorTxs); i++ {
332				l1 := args.L1CoordinatorTxs[i]
333				bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i])
334				if err != nil {
335					return nil, err
336				}
337				l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...)
338			}
339			var l2DataBytes []byte
340			for i := 0; i < len(args.L2TxsData); i++ {
341				l2 := args.L2TxsData[i]
342				bytesl2, err := l2.Bytes(int(nLevels))
343				if err != nil {
344					return nil, err
345				}
346				l2DataBytes = append(l2DataBytes, bytesl2[:]...)
347			}
348			var feeIdxCoordinator []byte
349			if len(args.FeeIdxCoordinator) > RollupConstMaxFeeIdxCoordinator {
350				return nil, fmt.Errorf("len(args.FeeIdxCoordinator) > %v",
351					RollupConstMaxFeeIdxCoordinator)
352			}
353			for i := 0; i < RollupConstMaxFeeIdxCoordinator; i++ {
354				feeIdx := common.Idx(0)
355				if i < len(args.FeeIdxCoordinator) {
356					feeIdx = args.FeeIdxCoordinator[i]
357				}
358				bytesFeeIdx, err := feeIdx.Bytes()
359				if err != nil {
360					return nil, err
361				}
362				feeIdxCoordinator = append(feeIdxCoordinator, bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...)
363			}
364			return c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, l1CoordinatorBytes, l2DataBytes, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, args.ProofA, args.ProofB, args.ProofC)
365		},
366	); err != nil {
367		return nil, fmt.Errorf("Failed forge batch: %w", err)
368	}
369	return tx, nil
370}
371
372// RollupAddToken is the interface to call the smart contract function.
373// `feeAddToken` is the amount of HEZ tokens that will be paid to add the
374// token.  `feeAddToken` must match the public value of the smart contract.
375func (c *RollupClient) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken *big.Int) (tx *types.Transaction, err error) {
376	if tx, err = c.client.CallAuth(
377		0,
378		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
379			tokens, err := ERC777.NewERC777(c.tokenHEZAddress, ec)
380			if err != nil {
381				return nil, err
382			}
383			addTokenFnSignature := []byte("addToken(address)")
384			hash := sha3.NewLegacyKeccak256()
385			_, err = hash.Write(addTokenFnSignature)
386			if err != nil {
387				return nil, err
388			}
389			methodID := hash.Sum(nil)[:4]
390			var data []byte
391			data = append(data, methodID...)
392			paddedAddress := ethCommon.LeftPadBytes(tokenAddress.Bytes(), 32)
393			data = append(data, paddedAddress[:]...)
394			return tokens.Send(auth, c.address, feeAddToken, data)
395		},
396	); err != nil {
397		return nil, fmt.Errorf("Failed add Token %w", err)
398	}
399	return tx, nil
400}
401
402// RollupWithdrawMerkleProof is the interface to call the smart contract function
403func (c *RollupClient) RollupWithdrawMerkleProof(fromBJJ *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) {
404	if tx, err = c.client.CallAuth(
405		0,
406		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
407			hermez, err := Hermez.NewHermez(c.address, ec)
408			if err != nil {
409				return nil, err
410			}
411			pkCompL := fromBJJ.Compress()
412			pkCompB := common.SwapEndianness(pkCompL[:])
413			babyPubKey := new(big.Int).SetBytes(pkCompB)
414			numExitRootB := big.NewInt(numExitRoot)
415			idxBig := big.NewInt(idx)
416			return hermez.WithdrawMerkleProof(auth, tokenID, amount, babyPubKey, numExitRootB, siblings, idxBig, instantWithdraw)
417		},
418	); err != nil {
419		return nil, fmt.Errorf("Failed update WithdrawMerkleProof: %w", err)
420	}
421	return tx, nil
422}
423
424// RollupWithdrawCircuit is the interface to call the smart contract function
425func (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) {
426	log.Error("TODO")
427	return nil, errTODO
428}
429
430// RollupL1UserTxERC20ETH is the interface to call the smart contract function
431func (c *RollupClient) RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (tx *types.Transaction, err error) {
432	if tx, err = c.client.CallAuth(
433		0,
434		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
435			hermez, err := Hermez.NewHermez(c.address, ec)
436			if err != nil {
437				return nil, err
438			}
439			pkCompL := fromBJJ.Compress()
440			pkCompB := common.SwapEndianness(pkCompL[:])
441			babyPubKey := new(big.Int).SetBytes(pkCompB)
442			fromIdxBig := big.NewInt(fromIdx)
443			toIdxBig := big.NewInt(toIdx)
444			tokenIDBig := uint32(tokenID)
445			loadAmountF, err := common.NewFloat16(loadAmount)
446			if err != nil {
447				return nil, err
448			}
449			amountF, err := common.NewFloat16(amount)
450			if err != nil {
451				return nil, err
452			}
453			if tokenID == 0 {
454				auth.Value = loadAmount
455			}
456			return hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(loadAmountF), uint16(amountF), tokenIDBig, toIdxBig)
457		},
458	); err != nil {
459		return nil, fmt.Errorf("Failed add L1 Tx ERC20/ETH: %w", err)
460	}
461	return tx, nil
462}
463
464// RollupL1UserTxERC777 is the interface to call the smart contract function
465func (c *RollupClient) RollupL1UserTxERC777(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (tx *types.Transaction, err error) {
466	if tx, err = c.client.CallAuth(
467		0,
468		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
469			tokens, err := ERC777.NewERC777(c.tokenHEZAddress, ec)
470			if err != nil {
471				return nil, err
472			}
473			addL1TxFnSignature := []byte("addL1Transaction(uint256,uint48,uint16,uint16,uint32,uint48)")
474			hash := sha3.NewLegacyKeccak256()
475			_, err = hash.Write(addL1TxFnSignature)
476			if err != nil {
477				return nil, err
478			}
479			methodID := hash.Sum(nil)[:4]
480			pkCompL := fromBJJ.Compress()
481			pkCompB := common.SwapEndianness(pkCompL[:])
482			paddedAddress := ethCommon.LeftPadBytes(pkCompB, 32)
483			fromIdxB, err := common.Idx(fromIdx).Bytes()
484			if err != nil {
485				return nil, err
486			}
487			paddedFromIdx := ethCommon.LeftPadBytes(fromIdxB[:], 32)
488			loadAmountF, err := common.NewFloat16(loadAmount)
489			if err != nil {
490				return nil, err
491			}
492			paddedLoadAmount := ethCommon.LeftPadBytes(loadAmountF.Bytes(), 32)
493			amountF, err := common.NewFloat16(amount)
494			if err != nil {
495				return nil, err
496			}
497			paddedAmount := ethCommon.LeftPadBytes(amountF.Bytes(), 32)
498			tokenIDB := common.TokenID(tokenID).Bytes()
499			paddedTokenID := ethCommon.LeftPadBytes(tokenIDB, 32)
500			toIdxB, err := common.Idx(toIdx).Bytes()
501			if err != nil {
502				return nil, err
503			}
504			paddedToIdx := ethCommon.LeftPadBytes(toIdxB[:], 32)
505			var data []byte
506			data = append(data, methodID...)
507			data = append(data, paddedAddress[:]...)
508			data = append(data, paddedFromIdx[:]...)
509			data = append(data, paddedLoadAmount[:]...)
510			data = append(data, paddedAmount[:]...)
511			data = append(data, paddedTokenID[:]...)
512			data = append(data, paddedToIdx[:]...)
513			return tokens.Send(auth, c.address, loadAmount, data)
514		},
515	); err != nil {
516		return nil, fmt.Errorf("Failed add L1 Tx ERC777: %w", err)
517	}
518	return tx, nil
519}
520
521// RollupRegisterTokensCount is the interface to call the smart contract function
522func (c *RollupClient) RollupRegisterTokensCount() (*big.Int, error) {
523	var registerTokensCount *big.Int
524	if err := c.client.Call(func(ec *ethclient.Client) error {
525		hermez, err := Hermez.NewHermez(c.address, ec)
526		if err != nil {
527			return err
528		}
529		registerTokensCount, err = hermez.RegisterTokensCount(nil)
530		return err
531	}); err != nil {
532		return nil, err
533	}
534	return registerTokensCount, nil
535}
536
537// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
538func (c *RollupClient) RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (tx *types.Transaction, err error) {
539	if tx, err = c.client.CallAuth(
540		0,
541		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
542			hermez, err := Hermez.NewHermez(c.address, ec)
543			if err != nil {
544				return nil, err
545			}
546			return hermez.UpdateForgeL1L2BatchTimeout(auth, uint8(newForgeL1L2BatchTimeout))
547		},
548	); err != nil {
549		return nil, fmt.Errorf("Failed update ForgeL1L2BatchTimeout: %w", err)
550	}
551	return tx, nil
552}
553
554// RollupUpdateFeeAddToken is the interface to call the smart contract function
555func (c *RollupClient) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
556	if tx, err = c.client.CallAuth(
557		0,
558		func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
559			hermez, err := Hermez.NewHermez(c.address, ec)
560			if err != nil {
561				return nil, err
562			}
563			return hermez.UpdateFeeAddToken(auth, newFeeAddToken)
564		},
565	); err != nil {
566		return nil, fmt.Errorf("Failed update FeeAddToken: %w", err)
567	}
568	return tx, nil
569}
570
571// RollupConstants returns the Constants of the Rollup Smart Contract
572func (c *RollupClient) RollupConstants() (rollupConstants *RollupPublicConstants, err error) {
573	rollupConstants = new(RollupPublicConstants)
574	if err := c.client.Call(func(ec *ethclient.Client) error {
575		absoluteMaxL1L2BatchTimeout, err := c.hermez.ABSOLUTEMAXL1L2BATCHTIMEOUT(nil)
576		if err != nil {
577			return err
578		}
579		rollupConstants.AbsoluteMaxL1L2BatchTimeout = int64(absoluteMaxL1L2BatchTimeout)
580		rollupConstants.TokenHEZ, err = c.hermez.TokenHEZ(nil)
581		if err != nil {
582			return err
583		}
584		for i := int64(0); i < int64(LenVerifiers); i++ {
585			var newRollupVerifier RollupVerifierStruct
586			rollupVerifier, err := c.hermez.RollupVerifiers(nil, big.NewInt(i))
587			if err != nil {
588				return err
589			}
590			newRollupVerifier.MaxTx = rollupVerifier.MaxTx.Int64()
591			newRollupVerifier.NLevels = rollupVerifier.NLevels.Int64()
592			rollupConstants.Verifiers = append(rollupConstants.Verifiers, newRollupVerifier)
593		}
594		rollupConstants.HermezAuctionContract, err = c.hermez.HermezAuctionContract(nil)
595		if err != nil {
596			return err
597		}
598		rollupConstants.HermezGovernanceDAOAddress, err = c.hermez.HermezGovernanceDAOAddress(nil)
599		if err != nil {
600			return err
601		}
602		rollupConstants.SafetyAddress, err = c.hermez.SafetyAddress(nil)
603		if err != nil {
604			return err
605		}
606		rollupConstants.WithdrawDelayerContract, err = c.hermez.WithdrawDelayerContract(nil)
607		return err
608	}); err != nil {
609		return nil, err
610	}
611	return rollupConstants, nil
612}
613
614var (
615	logHermezL1UserTxEvent               = crypto.Keccak256Hash([]byte("L1UserTxEvent(uint64,uint8,bytes)"))
616	logHermezAddToken                    = crypto.Keccak256Hash([]byte("AddToken(address,uint32)"))
617	logHermezForgeBatch                  = crypto.Keccak256Hash([]byte("ForgeBatch(uint64)"))
618	logHermezUpdateForgeL1L2BatchTimeout = crypto.Keccak256Hash([]byte("UpdateForgeL1L2BatchTimeout(uint8)"))
619	logHermezUpdateFeeAddToken           = crypto.Keccak256Hash([]byte("UpdateFeeAddToken(uint256)"))
620	logHermezWithdrawEvent               = crypto.Keccak256Hash([]byte("WithdrawEvent(uint48,uint48,bool)"))
621)
622
623// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
624func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) {
625	var rollupEvents RollupEvents
626	var blockHash ethCommon.Hash
627
628	query := ethereum.FilterQuery{
629		FromBlock: big.NewInt(blockNum),
630		ToBlock:   big.NewInt(blockNum),
631		Addresses: []ethCommon.Address{
632			c.address,
633		},
634		BlockHash: nil,
635		Topics:    [][]ethCommon.Hash{},
636	}
637	logs, err := c.client.client.FilterLogs(context.Background(), query)
638	if err != nil {
639		return nil, nil, err
640	}
641	if len(logs) > 0 {
642		blockHash = logs[0].BlockHash
643	}
644	for _, vLog := range logs {
645		if vLog.BlockHash != blockHash {
646			return nil, nil, ErrBlockHashMismatchEvent
647		}
648		switch vLog.Topics[0] {
649		case logHermezL1UserTxEvent:
650			var L1UserTxAux RollupEventL1UserTxAux
651			var L1UserTx RollupEventL1UserTx
652			err := c.contractAbi.Unpack(&L1UserTxAux, "L1UserTxEvent", vLog.Data)
653			if err != nil {
654				return nil, nil, err
655			}
656			L1Tx, err := common.L1UserTxFromBytes(L1UserTxAux.L1UserTx)
657			if err != nil {
658				return nil, nil, err
659			}
660			toForgeL1TxsNum := new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
661			L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
662			L1Tx.Position = int(new(big.Int).SetBytes(vLog.Topics[2][:]).Int64())
663			L1Tx.UserOrigin = true
664			L1UserTx.L1UserTx = *L1Tx
665			rollupEvents.L1UserTx = append(rollupEvents.L1UserTx, L1UserTx)
666		case logHermezAddToken:
667			var addToken RollupEventAddToken
668			err := c.contractAbi.Unpack(&addToken, "AddToken", vLog.Data)
669			if err != nil {
670				return nil, nil, err
671			}
672			addToken.TokenAddress = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
673			rollupEvents.AddToken = append(rollupEvents.AddToken, addToken)
674		case logHermezForgeBatch:
675			var forgeBatch RollupEventForgeBatch
676			forgeBatch.BatchNum = new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
677			forgeBatch.EthTxHash = vLog.TxHash
678			// forgeBatch.Sender = vLog.Address
679			rollupEvents.ForgeBatch = append(rollupEvents.ForgeBatch, forgeBatch)
680		case logHermezUpdateForgeL1L2BatchTimeout:
681			var updateForgeL1L2BatchTimeout struct {
682				NewForgeL1L2BatchTimeout uint8
683			}
684			err := c.contractAbi.Unpack(&updateForgeL1L2BatchTimeout, "UpdateForgeL1L2BatchTimeout", vLog.Data)
685			if err != nil {
686				return nil, nil, err
687			}
688			rollupEvents.UpdateForgeL1L2BatchTimeout = append(rollupEvents.UpdateForgeL1L2BatchTimeout,
689				RollupEventUpdateForgeL1L2BatchTimeout{
690					NewForgeL1L2BatchTimeout: int64(updateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout),
691				})
692		case logHermezUpdateFeeAddToken:
693			var updateFeeAddToken RollupEventUpdateFeeAddToken
694			err := c.contractAbi.Unpack(&updateFeeAddToken, "UpdateFeeAddToken", vLog.Data)
695			if err != nil {
696				return nil, nil, err
697			}
698			rollupEvents.UpdateFeeAddToken = append(rollupEvents.UpdateFeeAddToken, updateFeeAddToken)
699		case logHermezWithdrawEvent:
700			var withdraw RollupEventWithdrawEvent
701			withdraw.Idx = new(big.Int).SetBytes(vLog.Topics[1][:]).Uint64()
702			withdraw.NumExitRoot = new(big.Int).SetBytes(vLog.Topics[2][:]).Uint64()
703			instantWithdraw := new(big.Int).SetBytes(vLog.Topics[3][:]).Uint64()
704			if instantWithdraw == 1 {
705				withdraw.InstantWithdraw = true
706			}
707			rollupEvents.WithdrawEvent = append(rollupEvents.WithdrawEvent, withdraw)
708		}
709	}
710	return &rollupEvents, &blockHash, nil
711}
712
713// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the
714// Rollup Smart Contract in the given transaction, and the sender address.
715func (c *RollupClient) RollupForgeBatchArgs(ethTxHash ethCommon.Hash) (*RollupForgeBatchArgs, *ethCommon.Address, error) {
716	tx, _, err := c.client.client.TransactionByHash(context.Background(), ethTxHash)
717	if err != nil {
718		return nil, nil, err
719	}
720	txData := tx.Data()
721	method, err := c.contractAbi.MethodById(txData[:4])
722	if err != nil {
723		return nil, nil, err
724	}
725	receipt, err := c.client.client.TransactionReceipt(context.Background(), ethTxHash)
726	if err != nil {
727		return nil, nil, err
728	}
729	sender, err := c.client.client.TransactionSender(context.Background(), tx, receipt.Logs[0].BlockHash, receipt.Logs[0].Index)
730	if err != nil {
731		return nil, nil, err
732	}
733	var aux RollupForgeBatchArgsAux
734	if err := method.Inputs.Unpack(&aux, txData[4:]); err != nil {
735		return nil, nil, err
736	}
737	rollupForgeBatchArgs := RollupForgeBatchArgs{
738		L1Batch:               aux.L1Batch,
739		NewExitRoot:           aux.NewExitRoot,
740		NewLastIdx:            aux.NewLastIdx.Int64(),
741		NewStRoot:             aux.NewStRoot,
742		ProofA:                aux.ProofA,
743		ProofB:                aux.ProofB,
744		ProofC:                aux.ProofC,
745		VerifierIdx:           aux.VerifierIdx,
746		L1CoordinatorTxs:      []common.L1Tx{},
747		L1CoordinatorTxsAuths: [][]byte{},
748		L2TxsData:             []common.L2Tx{},
749		FeeIdxCoordinator:     []common.Idx{},
750	}
751	numTxsL1 := len(aux.EncodedL1CoordinatorTx) / common.L1CoordinatorTxBytesLen
752	for i := 0; i < numTxsL1; i++ {
753		bytesL1Coordinator := aux.EncodedL1CoordinatorTx[i*common.L1CoordinatorTxBytesLen : (i+1)*common.L1CoordinatorTxBytesLen]
754		var signature []byte
755		v := bytesL1Coordinator[0]
756		s := bytesL1Coordinator[1:33]
757		r := bytesL1Coordinator[33:65]
758		signature = append(signature, r[:]...)
759		signature = append(signature, s[:]...)
760		signature = append(signature, v)
761		l1Tx, err := common.L1CoordinatorTxFromBytes(bytesL1Coordinator)
762		if err != nil {
763			return nil, nil, err
764		}
765		rollupForgeBatchArgs.L1CoordinatorTxs = append(rollupForgeBatchArgs.L1CoordinatorTxs, *l1Tx)
766		rollupForgeBatchArgs.L1CoordinatorTxsAuths = append(rollupForgeBatchArgs.L1CoordinatorTxsAuths, signature)
767	}
768	rollupConsts, err := c.RollupConstants()
769	if err != nil {
770		return nil, nil, err
771	}
772	nLevels := rollupConsts.Verifiers[rollupForgeBatchArgs.VerifierIdx].NLevels
773	lenL2TxsBytes := int((nLevels/8)*2 + 2 + 1)
774	numTxsL2 := len(aux.L2TxsData) / lenL2TxsBytes
775	for i := 0; i < numTxsL2; i++ {
776		l2Tx, err := common.L2TxFromBytes(aux.L2TxsData[i*lenL2TxsBytes:(i+1)*lenL2TxsBytes], int(nLevels))
777		if err != nil {
778			return nil, nil, err
779		}
780		rollupForgeBatchArgs.L2TxsData = append(rollupForgeBatchArgs.L2TxsData, *l2Tx)
781	}
782	lenFeeIdxCoordinatorBytes := int(nLevels / 8) //nolint:gomnd
783	numFeeIdxCoordinator := len(aux.FeeIdxCoordinator) / lenFeeIdxCoordinatorBytes
784	for i := 0; i < numFeeIdxCoordinator; i++ {
785		var paddedFeeIdx [6]byte
786		// TODO: This check is not necessary: the first case will always work.  Test it before removing the if.
787		if lenFeeIdxCoordinatorBytes < common.IdxBytesLen {
788			copy(paddedFeeIdx[6-lenFeeIdxCoordinatorBytes:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
789		} else {
790			copy(paddedFeeIdx[:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
791		}
792		feeIdxCoordinator, err := common.IdxFromBytes(paddedFeeIdx[:])
793		if err != nil {
794			return nil, nil, err
795		}
796		if feeIdxCoordinator != common.Idx(0) {
797			rollupForgeBatchArgs.FeeIdxCoordinator = append(rollupForgeBatchArgs.FeeIdxCoordinator, feeIdxCoordinator)
798		}
799	}
800	return &rollupForgeBatchArgs, &sender, nil
801}