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