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