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