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