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