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