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