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