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