hermez-node/eth/rollup.go
eth/rollup.goRaw
1package eth
2
3import (
4 "context"
5 "fmt"
6 "math/big"
7 "strconv"
8 "strings"
9
10 "github.com/ethereum/go-ethereum"
11 "github.com/ethereum/go-ethereum/accounts/abi"
12 "github.com/ethereum/go-ethereum/accounts/abi/bind"
13 ethCommon "github.com/ethereum/go-ethereum/common"
14 "github.com/ethereum/go-ethereum/core/types"
15 "github.com/ethereum/go-ethereum/crypto"
16 "github.com/ethereum/go-ethereum/ethclient"
17 "github.com/hermeznetwork/hermez-node/common"
18 Hermez "github.com/hermeznetwork/hermez-node/eth/contracts/hermez"
19 HEZ "github.com/hermeznetwork/hermez-node/eth/contracts/tokenHEZ"
20 "github.com/hermeznetwork/hermez-node/log"
21 "github.com/hermeznetwork/tracerr"
22 "github.com/iden3/go-iden3-crypto/babyjub"
23)
24
25// QueueStruct is the queue of L1Txs for a batch
26type QueueStruct struct {
27 L1TxQueue []common.L1Tx
28 TotalL1TxFee *big.Int
29}
30
31// NewQueueStruct creates a new clear QueueStruct.
32func NewQueueStruct() *QueueStruct {
33 return &QueueStruct{
34 L1TxQueue: make([]common.L1Tx, 0),
35 TotalL1TxFee: big.NewInt(0),
36 }
37}
38
39// RollupState represents the state of the Rollup in the Smart Contract
40type RollupState struct {
41 StateRoot *big.Int
42 ExitRoots []*big.Int
43 // ExitNullifierMap map[[256 / 8]byte]bool
44 ExitNullifierMap map[int64]map[int64]bool // batchNum -> idx -> bool
45 TokenList []ethCommon.Address
46 TokenMap map[ethCommon.Address]bool
47 MapL1TxQueue map[int64]*QueueStruct
48 LastL1L2Batch int64
49 CurrentToForgeL1TxsNum int64
50 LastToForgeL1TxsNum int64
51 CurrentIdx int64
52}
53
54// RollupEventL1UserTx is an event of the Rollup Smart Contract
55type RollupEventL1UserTx struct {
56 // ToForgeL1TxsNum int64 // QueueIndex *big.Int
57 // Position int // TransactionIndex *big.Int
58 L1UserTx common.L1Tx
59}
60
61// RollupEventL1UserTxAux is an event of the Rollup Smart Contract
62type rollupEventL1UserTxAux struct {
63 ToForgeL1TxsNum uint64 // QueueIndex *big.Int
64 Position uint8 // TransactionIndex *big.Int
65 L1UserTx []byte
66}
67
68// RollupEventAddToken is an event of the Rollup Smart Contract
69type RollupEventAddToken struct {
70 TokenAddress ethCommon.Address
71 TokenID uint32
72}
73
74// RollupEventForgeBatch is an event of the Rollup Smart Contract
75type RollupEventForgeBatch struct {
76 BatchNum int64
77 // Sender ethCommon.Address
78 EthTxHash ethCommon.Hash
79 L1UserTxsLen uint16
80}
81
82// RollupEventUpdateForgeL1L2BatchTimeout is an event of the Rollup Smart Contract
83type RollupEventUpdateForgeL1L2BatchTimeout struct {
84 NewForgeL1L2BatchTimeout int64
85}
86
87// RollupEventUpdateFeeAddToken is an event of the Rollup Smart Contract
88type RollupEventUpdateFeeAddToken struct {
89 NewFeeAddToken *big.Int
90}
91
92// RollupEventWithdraw is an event of the Rollup Smart Contract
93type RollupEventWithdraw struct {
94 Idx uint64
95 NumExitRoot uint64
96 InstantWithdraw bool
97 TxHash ethCommon.Hash // Hash of the transaction that generated this event
98}
99
100type rollupEventUpdateBucketWithdrawAux struct {
101 NumBucket uint8
102 BlockStamp *big.Int
103 Withdrawals *big.Int
104}
105
106// RollupEventUpdateBucketWithdraw is an event of the Rollup Smart Contract
107type RollupEventUpdateBucketWithdraw struct {
108 NumBucket int
109 BlockStamp int64 // blockNum
110 Withdrawals *big.Int
111}
112
113// RollupEventUpdateWithdrawalDelay is an event of the Rollup Smart Contract
114type RollupEventUpdateWithdrawalDelay struct {
115 NewWithdrawalDelay uint64
116}
117
118// RollupUpdateBucketsParameters are the bucket parameters used in an update
119type RollupUpdateBucketsParameters struct {
120 CeilUSD *big.Int
121 Withdrawals *big.Int
122 BlockWithdrawalRate *big.Int
123 MaxWithdrawals *big.Int
124}
125
126type rollupEventUpdateBucketsParametersAux struct {
127 ArrayBuckets [common.RollupConstNumBuckets][4]*big.Int
128}
129
130// RollupEventUpdateBucketsParameters is an event of the Rollup Smart Contract
131type RollupEventUpdateBucketsParameters struct {
132 // ArrayBuckets [common.RollupConstNumBuckets][4]*big.Int
133 ArrayBuckets [common.RollupConstNumBuckets]RollupUpdateBucketsParameters
134}
135
136// RollupEventUpdateTokenExchange is an event of the Rollup Smart Contract
137type RollupEventUpdateTokenExchange struct {
138 AddressArray []ethCommon.Address
139 ValueArray []uint64
140}
141
142// RollupEventSafeMode is an event of the Rollup Smart Contract
143type RollupEventSafeMode struct {
144}
145
146// RollupEvents is the list of events in a block of the Rollup Smart Contract
147type RollupEvents struct {
148 L1UserTx []RollupEventL1UserTx
149 AddToken []RollupEventAddToken
150 ForgeBatch []RollupEventForgeBatch
151 UpdateForgeL1L2BatchTimeout []RollupEventUpdateForgeL1L2BatchTimeout
152 UpdateFeeAddToken []RollupEventUpdateFeeAddToken
153 Withdraw []RollupEventWithdraw
154 UpdateWithdrawalDelay []RollupEventUpdateWithdrawalDelay
155 UpdateBucketWithdraw []RollupEventUpdateBucketWithdraw
156 UpdateBucketsParameters []RollupEventUpdateBucketsParameters
157 UpdateTokenExchange []RollupEventUpdateTokenExchange
158 SafeMode []RollupEventSafeMode
159}
160
161// NewRollupEvents creates an empty RollupEvents with the slices initialized.
162func NewRollupEvents() RollupEvents {
163 return RollupEvents{
164 L1UserTx: make([]RollupEventL1UserTx, 0),
165 AddToken: make([]RollupEventAddToken, 0),
166 ForgeBatch: make([]RollupEventForgeBatch, 0),
167 UpdateForgeL1L2BatchTimeout: make([]RollupEventUpdateForgeL1L2BatchTimeout, 0),
168 UpdateFeeAddToken: make([]RollupEventUpdateFeeAddToken, 0),
169 Withdraw: make([]RollupEventWithdraw, 0),
170 }
171}
172
173// RollupForgeBatchArgs are the arguments to the ForgeBatch function in the Rollup Smart Contract
174type RollupForgeBatchArgs struct {
175 NewLastIdx int64
176 NewStRoot *big.Int
177 NewExitRoot *big.Int
178 L1UserTxs []common.L1Tx
179 L1CoordinatorTxs []common.L1Tx
180 L1CoordinatorTxsAuths [][]byte // Authorization for accountCreations for each L1CoordinatorTx
181 L2TxsData []common.L2Tx
182 FeeIdxCoordinator []common.Idx
183 // Circuit selector
184 VerifierIdx uint8
185 L1Batch bool
186 ProofA [2]*big.Int
187 ProofB [2][2]*big.Int
188 ProofC [2]*big.Int
189}
190
191// RollupForgeBatchArgsAux are the arguments to the ForgeBatch function in the Rollup Smart Contract
192type rollupForgeBatchArgsAux struct {
193 NewLastIdx *big.Int
194 NewStRoot *big.Int
195 NewExitRoot *big.Int
196 EncodedL1CoordinatorTx []byte
197 L1L2TxsData []byte
198 FeeIdxCoordinator []byte
199 // Circuit selector
200 VerifierIdx uint8
201 L1Batch bool
202 ProofA [2]*big.Int
203 ProofB [2][2]*big.Int
204 ProofC [2]*big.Int
205}
206
207// RollupInterface is the inteface to to Rollup Smart Contract
208type RollupInterface interface {
209 //
210 // Smart Contract Methods
211 //
212
213 // Public Functions
214
215 RollupForgeBatch(*RollupForgeBatchArgs) (*types.Transaction, error)
216 RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (*types.Transaction, error)
217
218 RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error)
219 RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error)
220
221 RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error)
222 RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error)
223
224 // Governance Public Functions
225 RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (*types.Transaction, error)
226 RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (*types.Transaction, error)
227
228 // Viewers
229 RollupRegisterTokensCount() (*big.Int, error)
230 RollupLastForgedBatch() (int64, error)
231
232 //
233 // Smart Contract Status
234 //
235
236 RollupConstants() (*common.RollupConstants, error)
237 RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error)
238 RollupForgeBatchArgs(ethCommon.Hash, uint16) (*RollupForgeBatchArgs, *ethCommon.Address, error)
239}
240
241//
242// Implementation
243//
244
245// RollupClient is the implementation of the interface to the Rollup Smart Contract in ethereum.
246type RollupClient struct {
247 client *EthereumClient
248 chainID *big.Int
249 address ethCommon.Address
250 tokenHEZCfg TokenConfig
251 hermez *Hermez.Hermez
252 tokenHEZ *HEZ.HEZ
253 contractAbi abi.ABI
254}
255
256// NewRollupClient creates a new RollupClient
257func NewRollupClient(client *EthereumClient, address ethCommon.Address, tokenHEZCfg TokenConfig) (*RollupClient, error) {
258 contractAbi, err := abi.JSON(strings.NewReader(string(Hermez.HermezABI)))
259 if err != nil {
260 return nil, tracerr.Wrap(err)
261 }
262 hermez, err := Hermez.NewHermez(address, client.Client())
263 if err != nil {
264 return nil, tracerr.Wrap(err)
265 }
266 tokenHEZ, err := HEZ.NewHEZ(tokenHEZCfg.Address, client.Client())
267 if err != nil {
268 return nil, tracerr.Wrap(err)
269 }
270 chainID, err := client.client.ChainID(context.Background())
271 if err != nil {
272 return nil, tracerr.Wrap(err)
273 }
274 return &RollupClient{
275 client: client,
276 chainID: chainID,
277 address: address,
278 tokenHEZCfg: tokenHEZCfg,
279 hermez: hermez,
280 tokenHEZ: tokenHEZ,
281 contractAbi: contractAbi,
282 }, nil
283}
284
285// RollupForgeBatch is the interface to call the smart contract function
286func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (tx *types.Transaction, err error) {
287 if tx, err = c.client.CallAuth(
288 1000000, //nolint:gomnd
289 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
290 rollupConst, err := c.RollupConstants()
291 if err != nil {
292 return nil, tracerr.Wrap(err)
293 }
294 nLevels := rollupConst.Verifiers[args.VerifierIdx].NLevels
295 lenBytes := nLevels / 8 //nolint:gomnd
296 newLastIdx := big.NewInt(int64(args.NewLastIdx))
297 // L1CoordinatorBytes
298 var l1CoordinatorBytes []byte
299 for i := 0; i < len(args.L1CoordinatorTxs); i++ {
300 l1 := args.L1CoordinatorTxs[i]
301 bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i])
302 if err != nil {
303 return nil, tracerr.Wrap(err)
304 }
305 l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...)
306 }
307 // L1L2TxData
308 var l1l2TxData []byte
309 for i := 0; i < len(args.L1UserTxs); i++ {
310 l1User := args.L1UserTxs[i]
311 bytesl1User, err := l1User.BytesDataAvailability(uint32(nLevels))
312 if err != nil {
313 return nil, tracerr.Wrap(err)
314 }
315 l1l2TxData = append(l1l2TxData, bytesl1User[:]...)
316 }
317 for i := 0; i < len(args.L1CoordinatorTxs); i++ {
318 l1Coord := args.L1CoordinatorTxs[i]
319 bytesl1Coord, err := l1Coord.BytesDataAvailability(uint32(nLevels))
320 if err != nil {
321 return nil, tracerr.Wrap(err)
322 }
323 l1l2TxData = append(l1l2TxData, bytesl1Coord[:]...)
324 }
325 for i := 0; i < len(args.L2TxsData); i++ {
326 l2 := args.L2TxsData[i]
327 bytesl2, err := l2.BytesDataAvailability(uint32(nLevels))
328 if err != nil {
329 return nil, tracerr.Wrap(err)
330 }
331 l1l2TxData = append(l1l2TxData, bytesl2[:]...)
332 }
333 // FeeIdxCoordinator
334 var feeIdxCoordinator []byte
335 if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator {
336 return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v",
337 common.RollupConstMaxFeeIdxCoordinator))
338 }
339 for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ {
340 feeIdx := common.Idx(0)
341 if i < len(args.FeeIdxCoordinator) {
342 feeIdx = args.FeeIdxCoordinator[i]
343 }
344 bytesFeeIdx, err := feeIdx.Bytes()
345 if err != nil {
346 return nil, tracerr.Wrap(err)
347 }
348 feeIdxCoordinator = append(feeIdxCoordinator, bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...)
349 }
350 return c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, l1CoordinatorBytes, l1l2TxData, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, args.ProofA, args.ProofB, args.ProofC)
351 },
352 ); err != nil {
353 return nil, tracerr.Wrap(fmt.Errorf("Failed forge batch: %w", err))
354 }
355 return tx, nil
356}
357
358// RollupAddToken is the interface to call the smart contract function.
359// `feeAddToken` is the amount of HEZ tokens that will be paid to add the
360// token. `feeAddToken` must match the public value of the smart contract.
361func (c *RollupClient) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (tx *types.Transaction, err error) {
362 if tx, err = c.client.CallAuth(
363 0,
364 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
365 owner := c.client.account.Address
366 spender := c.address
367 nonce, err := c.tokenHEZ.Nonces(nil, owner)
368 if err != nil {
369 return nil, tracerr.Wrap(err)
370 }
371 tokenName := c.tokenHEZCfg.Name
372 tokenAddr := c.tokenHEZCfg.Address
373 digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, feeAddToken, nonce, deadline, tokenName)
374 signature, _ := c.client.ks.SignHash(*c.client.account, digest)
375 permit := createPermit(owner, spender, feeAddToken, deadline, digest, signature)
376
377 return c.hermez.AddToken(auth, tokenAddress, permit)
378 },
379 ); err != nil {
380 return nil, tracerr.Wrap(fmt.Errorf("Failed add Token %w", err))
381 }
382 return tx, nil
383}
384
385// RollupWithdrawMerkleProof is the interface to call the smart contract function
386func (c *RollupClient) RollupWithdrawMerkleProof(fromBJJ *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) {
387 if tx, err = c.client.CallAuth(
388 0,
389 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
390 pkCompL := fromBJJ.Compress()
391 pkCompB := common.SwapEndianness(pkCompL[:])
392 babyPubKey := new(big.Int).SetBytes(pkCompB)
393 numExitRootB := uint32(numExitRoot)
394 idxBig := big.NewInt(idx)
395 return c.hermez.WithdrawMerkleProof(auth, tokenID, amount, babyPubKey, numExitRootB, siblings, idxBig, instantWithdraw)
396 },
397 ); err != nil {
398 return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawMerkleProof: %w", err))
399 }
400 return tx, nil
401}
402
403// RollupWithdrawCircuit is the interface to call the smart contract function
404func (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) {
405 log.Error("TODO")
406 return nil, tracerr.Wrap(errTODO)
407}
408
409// RollupL1UserTxERC20ETH is the interface to call the smart contract function
410func (c *RollupClient) RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (tx *types.Transaction, err error) {
411 if tx, err = c.client.CallAuth(
412 0,
413 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
414 var babyPubKey *big.Int
415 if fromBJJ != nil {
416 pkCompL := fromBJJ.Compress()
417 pkCompB := common.SwapEndianness(pkCompL[:])
418 babyPubKey = new(big.Int).SetBytes(pkCompB)
419 } else {
420 babyPubKey = big.NewInt(0)
421 }
422 fromIdxBig := big.NewInt(fromIdx)
423 toIdxBig := big.NewInt(toIdx)
424 loadAmountF, err := common.NewFloat16(loadAmount)
425 if err != nil {
426 return nil, tracerr.Wrap(err)
427 }
428 amountF, err := common.NewFloat16(amount)
429 if err != nil {
430 return nil, tracerr.Wrap(err)
431 }
432 if tokenID == 0 {
433 auth.Value = loadAmount
434 }
435 var permit []byte
436 return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(loadAmountF),
437 uint16(amountF), tokenID, toIdxBig, permit)
438 },
439 ); err != nil {
440 return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20/ETH: %w", err))
441 }
442 return tx, nil
443}
444
445// RollupL1UserTxERC20Permit is the interface to call the smart contract function
446func (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) {
447 if tx, err = c.client.CallAuth(
448 0,
449 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
450 var babyPubKey *big.Int
451 if fromBJJ != nil {
452 pkCompL := fromBJJ.Compress()
453 pkCompB := common.SwapEndianness(pkCompL[:])
454 babyPubKey = new(big.Int).SetBytes(pkCompB)
455 } else {
456 babyPubKey = big.NewInt(0)
457 }
458 fromIdxBig := big.NewInt(fromIdx)
459 toIdxBig := big.NewInt(toIdx)
460 loadAmountF, err := common.NewFloat16(loadAmount)
461 if err != nil {
462 return nil, tracerr.Wrap(err)
463 }
464 amountF, err := common.NewFloat16(amount)
465 if err != nil {
466 return nil, tracerr.Wrap(err)
467 }
468 if tokenID == 0 {
469 auth.Value = loadAmount
470 }
471 owner := c.client.account.Address
472 spender := c.address
473 nonce, err := c.tokenHEZ.Nonces(nil, owner)
474 if err != nil {
475 return nil, tracerr.Wrap(err)
476 }
477 tokenName := c.tokenHEZCfg.Name
478 tokenAddr := c.tokenHEZCfg.Address
479 digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, amount, nonce, deadline, tokenName)
480 signature, _ := c.client.ks.SignHash(*c.client.account, digest)
481 permit := createPermit(owner, spender, amount, deadline, digest, signature)
482 return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(loadAmountF),
483 uint16(amountF), tokenID, toIdxBig, permit)
484 },
485 ); err != nil {
486 return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20Permit: %w", err))
487 }
488 return tx, nil
489}
490
491// RollupRegisterTokensCount is the interface to call the smart contract function
492func (c *RollupClient) RollupRegisterTokensCount() (registerTokensCount *big.Int, err error) {
493 if err := c.client.Call(func(ec *ethclient.Client) error {
494 registerTokensCount, err = c.hermez.RegisterTokensCount(nil)
495 return tracerr.Wrap(err)
496 }); err != nil {
497 return nil, tracerr.Wrap(err)
498 }
499 return registerTokensCount, nil
500}
501
502// RollupLastForgedBatch is the interface to call the smart contract function
503func (c *RollupClient) RollupLastForgedBatch() (lastForgedBatch int64, err error) {
504 if err := c.client.Call(func(ec *ethclient.Client) error {
505 _lastForgedBatch, err := c.hermez.LastForgedBatch(nil)
506 lastForgedBatch = int64(_lastForgedBatch)
507 return tracerr.Wrap(err)
508 }); err != nil {
509 return 0, tracerr.Wrap(err)
510 }
511 return lastForgedBatch, nil
512}
513
514// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
515func (c *RollupClient) RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (tx *types.Transaction, err error) {
516 if tx, err = c.client.CallAuth(
517 0,
518 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
519 return c.hermez.UpdateForgeL1L2BatchTimeout(auth, uint8(newForgeL1L2BatchTimeout))
520 },
521 ); err != nil {
522 return nil, tracerr.Wrap(fmt.Errorf("Failed update ForgeL1L2BatchTimeout: %w", err))
523 }
524 return tx, nil
525}
526
527// RollupUpdateFeeAddToken is the interface to call the smart contract function
528func (c *RollupClient) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
529 if tx, err = c.client.CallAuth(
530 0,
531 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
532 return c.hermez.UpdateFeeAddToken(auth, newFeeAddToken)
533 },
534 ); err != nil {
535 return nil, tracerr.Wrap(fmt.Errorf("Failed update FeeAddToken: %w", err))
536 }
537 return tx, nil
538}
539
540// RollupUpdateBucketsParameters is the interface to call the smart contract function
541func (c *RollupClient) RollupUpdateBucketsParameters(
542 arrayBuckets [common.RollupConstNumBuckets]RollupUpdateBucketsParameters,
543) (tx *types.Transaction, err error) {
544 params := [common.RollupConstNumBuckets][4]*big.Int{}
545 for i, bucket := range arrayBuckets {
546 params[i][0] = bucket.CeilUSD
547 params[i][1] = bucket.Withdrawals
548 params[i][2] = bucket.BlockWithdrawalRate
549 params[i][3] = bucket.MaxWithdrawals
550 }
551 if tx, err = c.client.CallAuth(
552 12500000, //nolint:gomnd
553 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
554 return c.hermez.UpdateBucketsParameters(auth, params)
555 },
556 ); err != nil {
557 return nil, tracerr.Wrap(fmt.Errorf("Failed update Buckets Parameters: %w", err))
558 }
559 return tx, nil
560}
561
562// RollupUpdateTokenExchange is the interface to call the smart contract function
563func (c *RollupClient) RollupUpdateTokenExchange(addressArray []ethCommon.Address, valueArray []uint64) (tx *types.Transaction, err error) {
564 if tx, err = c.client.CallAuth(
565 0,
566 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
567 return c.hermez.UpdateTokenExchange(auth, addressArray, valueArray)
568 },
569 ); err != nil {
570 return nil, tracerr.Wrap(fmt.Errorf("Failed update Token Exchange: %w", err))
571 }
572 return tx, nil
573}
574
575// RollupUpdateWithdrawalDelay is the interface to call the smart contract function
576func (c *RollupClient) RollupUpdateWithdrawalDelay(newWithdrawalDelay int64) (tx *types.Transaction, err error) {
577 if tx, err = c.client.CallAuth(
578 0,
579 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
580 return c.hermez.UpdateWithdrawalDelay(auth, uint64(newWithdrawalDelay))
581 },
582 ); err != nil {
583 return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawalDelay: %w", err))
584 }
585 return tx, nil
586}
587
588// RollupSafeMode is the interface to call the smart contract function
589func (c *RollupClient) RollupSafeMode() (tx *types.Transaction, err error) {
590 if tx, err = c.client.CallAuth(
591 0,
592 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
593 return c.hermez.SafeMode(auth)
594 },
595 ); err != nil {
596 return nil, tracerr.Wrap(fmt.Errorf("Failed update Safe Mode: %w", err))
597 }
598 return tx, nil
599}
600
601// RollupInstantWithdrawalViewer is the interface to call the smart contract function
602func (c *RollupClient) RollupInstantWithdrawalViewer(tokenAddress ethCommon.Address, amount *big.Int) (instantAllowed bool, err error) {
603 if err := c.client.Call(func(ec *ethclient.Client) error {
604 instantAllowed, err = c.hermez.InstantWithdrawalViewer(nil, tokenAddress, amount)
605 return tracerr.Wrap(err)
606 }); err != nil {
607 return false, tracerr.Wrap(err)
608 }
609 return instantAllowed, nil
610}
611
612// RollupConstants returns the Constants of the Rollup Smart Contract
613func (c *RollupClient) RollupConstants() (rollupConstants *common.RollupConstants, err error) {
614 rollupConstants = new(common.RollupConstants)
615 if err := c.client.Call(func(ec *ethclient.Client) error {
616 absoluteMaxL1L2BatchTimeout, err := c.hermez.ABSOLUTEMAXL1L2BATCHTIMEOUT(nil)
617 if err != nil {
618 return tracerr.Wrap(err)
619 }
620 rollupConstants.AbsoluteMaxL1L2BatchTimeout = int64(absoluteMaxL1L2BatchTimeout)
621 rollupConstants.TokenHEZ, err = c.hermez.TokenHEZ(nil)
622 if err != nil {
623 return tracerr.Wrap(err)
624 }
625 for i := int64(0); i < int64(common.LenVerifiers); i++ {
626 var newRollupVerifier common.RollupVerifierStruct
627 rollupVerifier, err := c.hermez.RollupVerifiers(nil, big.NewInt(i))
628 if err != nil {
629 return tracerr.Wrap(err)
630 }
631 newRollupVerifier.MaxTx = rollupVerifier.MaxTx.Int64()
632 newRollupVerifier.NLevels = rollupVerifier.NLevels.Int64()
633 rollupConstants.Verifiers = append(rollupConstants.Verifiers, newRollupVerifier)
634 }
635 rollupConstants.HermezAuctionContract, err = c.hermez.HermezAuctionContract(nil)
636 if err != nil {
637 return tracerr.Wrap(err)
638 }
639 rollupConstants.HermezGovernanceAddress, err = c.hermez.HermezGovernanceAddress(nil)
640 if err != nil {
641 return tracerr.Wrap(err)
642 }
643 rollupConstants.WithdrawDelayerContract, err = c.hermez.WithdrawDelayerContract(nil)
644 return tracerr.Wrap(err)
645 }); err != nil {
646 return nil, tracerr.Wrap(err)
647 }
648 return rollupConstants, nil
649}
650
651var (
652 logHermezL1UserTxEvent = crypto.Keccak256Hash([]byte("L1UserTxEvent(uint32,uint8,bytes)"))
653 logHermezAddToken = crypto.Keccak256Hash([]byte("AddToken(address,uint32)"))
654 logHermezForgeBatch = crypto.Keccak256Hash([]byte("ForgeBatch(uint32,uint16)"))
655 logHermezUpdateForgeL1L2BatchTimeout = crypto.Keccak256Hash([]byte("UpdateForgeL1L2BatchTimeout(uint8)"))
656 logHermezUpdateFeeAddToken = crypto.Keccak256Hash([]byte("UpdateFeeAddToken(uint256)"))
657 logHermezWithdrawEvent = crypto.Keccak256Hash([]byte("WithdrawEvent(uint48,uint32,bool)"))
658 logHermezUpdateBucketWithdraw = crypto.Keccak256Hash([]byte("UpdateBucketWithdraw(uint8,uint256,uint256)"))
659 logHermezUpdateWithdrawalDelay = crypto.Keccak256Hash([]byte("UpdateWithdrawalDelay(uint64)"))
660 logHermezUpdateBucketsParameters = crypto.Keccak256Hash([]byte("UpdateBucketsParameters(uint256[4][" + strconv.Itoa(common.RollupConstNumBuckets) + "])"))
661 logHermezUpdateTokenExchange = crypto.Keccak256Hash([]byte("UpdateTokenExchange(address[],uint64[])"))
662 logHermezSafeMode = crypto.Keccak256Hash([]byte("SafeMode()"))
663)
664
665// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
666func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) {
667 var rollupEvents RollupEvents
668 var blockHash *ethCommon.Hash
669
670 query := ethereum.FilterQuery{
671 FromBlock: big.NewInt(blockNum),
672 ToBlock: big.NewInt(blockNum),
673 Addresses: []ethCommon.Address{
674 c.address,
675 },
676 BlockHash: nil,
677 Topics: [][]ethCommon.Hash{},
678 }
679 logs, err := c.client.client.FilterLogs(context.Background(), query)
680 if err != nil {
681 return nil, nil, tracerr.Wrap(err)
682 }
683 if len(logs) > 0 {
684 blockHash = &logs[0].BlockHash
685 }
686 for _, vLog := range logs {
687 if vLog.BlockHash != *blockHash {
688 log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String())
689 return nil, nil, tracerr.Wrap(ErrBlockHashMismatchEvent)
690 }
691 switch vLog.Topics[0] {
692 case logHermezL1UserTxEvent:
693 var L1UserTxAux rollupEventL1UserTxAux
694 var L1UserTx RollupEventL1UserTx
695 err := c.contractAbi.Unpack(&L1UserTxAux, "L1UserTxEvent", vLog.Data)
696 if err != nil {
697 return nil, nil, tracerr.Wrap(err)
698 }
699 L1Tx, err := common.L1UserTxFromBytes(L1UserTxAux.L1UserTx)
700 if err != nil {
701 return nil, nil, tracerr.Wrap(err)
702 }
703 toForgeL1TxsNum := new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
704 L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
705 L1Tx.Position = int(new(big.Int).SetBytes(vLog.Topics[2][:]).Int64())
706 L1Tx.UserOrigin = true
707 L1UserTx.L1UserTx = *L1Tx
708 rollupEvents.L1UserTx = append(rollupEvents.L1UserTx, L1UserTx)
709 case logHermezAddToken:
710 var addToken RollupEventAddToken
711 err := c.contractAbi.Unpack(&addToken, "AddToken", vLog.Data)
712 if err != nil {
713 return nil, nil, tracerr.Wrap(err)
714 }
715 addToken.TokenAddress = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
716 rollupEvents.AddToken = append(rollupEvents.AddToken, addToken)
717 case logHermezForgeBatch:
718 var forgeBatch RollupEventForgeBatch
719 err := c.contractAbi.Unpack(&forgeBatch, "ForgeBatch", vLog.Data)
720 if err != nil {
721 return nil, nil, tracerr.Wrap(err)
722 }
723 forgeBatch.BatchNum = new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
724 forgeBatch.EthTxHash = vLog.TxHash
725 // forgeBatch.Sender = vLog.Address
726 rollupEvents.ForgeBatch = append(rollupEvents.ForgeBatch, forgeBatch)
727 case logHermezUpdateForgeL1L2BatchTimeout:
728 var updateForgeL1L2BatchTimeout struct {
729 NewForgeL1L2BatchTimeout uint8
730 }
731 err := c.contractAbi.Unpack(&updateForgeL1L2BatchTimeout, "UpdateForgeL1L2BatchTimeout", vLog.Data)
732 if err != nil {
733 return nil, nil, tracerr.Wrap(err)
734 }
735 rollupEvents.UpdateForgeL1L2BatchTimeout = append(rollupEvents.UpdateForgeL1L2BatchTimeout,
736 RollupEventUpdateForgeL1L2BatchTimeout{
737 NewForgeL1L2BatchTimeout: int64(updateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout),
738 })
739 case logHermezUpdateFeeAddToken:
740 var updateFeeAddToken RollupEventUpdateFeeAddToken
741 err := c.contractAbi.Unpack(&updateFeeAddToken, "UpdateFeeAddToken", vLog.Data)
742 if err != nil {
743 return nil, nil, tracerr.Wrap(err)
744 }
745 rollupEvents.UpdateFeeAddToken = append(rollupEvents.UpdateFeeAddToken, updateFeeAddToken)
746 case logHermezWithdrawEvent:
747 var withdraw RollupEventWithdraw
748 withdraw.Idx = new(big.Int).SetBytes(vLog.Topics[1][:]).Uint64()
749 withdraw.NumExitRoot = new(big.Int).SetBytes(vLog.Topics[2][:]).Uint64()
750 instantWithdraw := new(big.Int).SetBytes(vLog.Topics[3][:]).Uint64()
751 if instantWithdraw == 1 {
752 withdraw.InstantWithdraw = true
753 }
754 withdraw.TxHash = vLog.TxHash
755 rollupEvents.Withdraw = append(rollupEvents.Withdraw, withdraw)
756 case logHermezUpdateBucketWithdraw:
757 var updateBucketWithdrawAux rollupEventUpdateBucketWithdrawAux
758 var updateBucketWithdraw RollupEventUpdateBucketWithdraw
759 err := c.contractAbi.Unpack(&updateBucketWithdrawAux, "UpdateBucketWithdraw", vLog.Data)
760 if err != nil {
761 return nil, nil, tracerr.Wrap(err)
762 }
763 updateBucketWithdraw.Withdrawals = updateBucketWithdrawAux.Withdrawals
764 updateBucketWithdraw.NumBucket = int(new(big.Int).SetBytes(vLog.Topics[1][:]).Int64())
765 updateBucketWithdraw.BlockStamp = new(big.Int).SetBytes(vLog.Topics[2][:]).Int64()
766 rollupEvents.UpdateBucketWithdraw = append(rollupEvents.UpdateBucketWithdraw, updateBucketWithdraw)
767
768 case logHermezUpdateWithdrawalDelay:
769 var withdrawalDelay RollupEventUpdateWithdrawalDelay
770 err := c.contractAbi.Unpack(&withdrawalDelay, "UpdateWithdrawalDelay", vLog.Data)
771 if err != nil {
772 return nil, nil, tracerr.Wrap(err)
773 }
774 rollupEvents.UpdateWithdrawalDelay = append(rollupEvents.UpdateWithdrawalDelay, withdrawalDelay)
775 case logHermezUpdateBucketsParameters:
776 var bucketsParametersAux rollupEventUpdateBucketsParametersAux
777 var bucketsParameters RollupEventUpdateBucketsParameters
778 err := c.contractAbi.Unpack(&bucketsParametersAux, "UpdateBucketsParameters", vLog.Data)
779 if err != nil {
780 return nil, nil, tracerr.Wrap(err)
781 }
782 for i, bucket := range bucketsParametersAux.ArrayBuckets {
783 bucketsParameters.ArrayBuckets[i].CeilUSD = bucket[0]
784 bucketsParameters.ArrayBuckets[i].Withdrawals = bucket[1]
785 bucketsParameters.ArrayBuckets[i].BlockWithdrawalRate = bucket[2]
786 bucketsParameters.ArrayBuckets[i].MaxWithdrawals = bucket[3]
787 }
788 rollupEvents.UpdateBucketsParameters = append(rollupEvents.UpdateBucketsParameters, bucketsParameters)
789 case logHermezUpdateTokenExchange:
790 var tokensExchange RollupEventUpdateTokenExchange
791 err := c.contractAbi.Unpack(&tokensExchange, "UpdateTokenExchange", vLog.Data)
792 if err != nil {
793 return nil, nil, tracerr.Wrap(err)
794 }
795 rollupEvents.UpdateTokenExchange = append(rollupEvents.UpdateTokenExchange, tokensExchange)
796 case logHermezSafeMode:
797 var safeMode RollupEventSafeMode
798 rollupEvents.SafeMode = append(rollupEvents.SafeMode, safeMode)
799 }
800 }
801 return &rollupEvents, blockHash, nil
802}
803
804// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the
805// Rollup Smart Contract in the given transaction, and the sender address.
806func (c *RollupClient) RollupForgeBatchArgs(ethTxHash ethCommon.Hash, l1UserTxsLen uint16) (*RollupForgeBatchArgs, *ethCommon.Address, error) {
807 tx, _, err := c.client.client.TransactionByHash(context.Background(), ethTxHash)
808 if err != nil {
809 return nil, nil, tracerr.Wrap(err)
810 }
811 txData := tx.Data()
812
813 method, err := c.contractAbi.MethodById(txData[:4])
814 if err != nil {
815 return nil, nil, tracerr.Wrap(err)
816 }
817 receipt, err := c.client.client.TransactionReceipt(context.Background(), ethTxHash)
818 if err != nil {
819 return nil, nil, tracerr.Wrap(err)
820 }
821 sender, err := c.client.client.TransactionSender(context.Background(), tx, receipt.Logs[0].BlockHash, receipt.Logs[0].Index)
822 if err != nil {
823 return nil, nil, tracerr.Wrap(err)
824 }
825 var aux rollupForgeBatchArgsAux
826 if err := method.Inputs.Unpack(&aux, txData[4:]); err != nil {
827 return nil, nil, tracerr.Wrap(err)
828 }
829 rollupForgeBatchArgs := RollupForgeBatchArgs{
830 L1Batch: aux.L1Batch,
831 NewExitRoot: aux.NewExitRoot,
832 NewLastIdx: aux.NewLastIdx.Int64(),
833 NewStRoot: aux.NewStRoot,
834 ProofA: aux.ProofA,
835 ProofB: aux.ProofB,
836 ProofC: aux.ProofC,
837 VerifierIdx: aux.VerifierIdx,
838 L1CoordinatorTxs: []common.L1Tx{},
839 L1CoordinatorTxsAuths: [][]byte{},
840 L2TxsData: []common.L2Tx{},
841 FeeIdxCoordinator: []common.Idx{},
842 }
843 rollupConsts, err := c.RollupConstants()
844 if err != nil {
845 return nil, nil, tracerr.Wrap(err)
846 }
847 nLevels := rollupConsts.Verifiers[rollupForgeBatchArgs.VerifierIdx].NLevels
848 lenL1L2TxsBytes := int((nLevels/8)*2 + 2 + 1)
849 numBytesL1TxUser := int(l1UserTxsLen) * lenL1L2TxsBytes
850 numTxsL1Coord := len(aux.EncodedL1CoordinatorTx) / common.L1CoordinatorTxBytesLen
851 numBytesL1TxCoord := numTxsL1Coord * lenL1L2TxsBytes
852 numBeginL2Tx := numBytesL1TxCoord + numBytesL1TxUser
853 l1UserTxsData := []byte{}
854 if l1UserTxsLen > 0 {
855 l1UserTxsData = aux.L1L2TxsData[:numBytesL1TxUser]
856 }
857 for i := 0; i < int(l1UserTxsLen); i++ {
858 l1Tx, err := common.L1TxFromDataAvailability(l1UserTxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], uint32(nLevels))
859 if err != nil {
860 return nil, nil, tracerr.Wrap(err)
861 }
862 rollupForgeBatchArgs.L1UserTxs = append(rollupForgeBatchArgs.L1UserTxs, *l1Tx)
863 }
864 l2TxsData := []byte{}
865 if numBeginL2Tx < len(aux.L1L2TxsData) {
866 l2TxsData = aux.L1L2TxsData[numBeginL2Tx:]
867 }
868 numTxsL2 := len(l2TxsData) / lenL1L2TxsBytes
869 for i := 0; i < numTxsL2; i++ {
870 l2Tx, err := common.L2TxFromBytesDataAvailability(l2TxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], int(nLevels))
871 if err != nil {
872 return nil, nil, tracerr.Wrap(err)
873 }
874 rollupForgeBatchArgs.L2TxsData = append(rollupForgeBatchArgs.L2TxsData, *l2Tx)
875 }
876 for i := 0; i < numTxsL1Coord; i++ {
877 bytesL1Coordinator := aux.EncodedL1CoordinatorTx[i*common.L1CoordinatorTxBytesLen : (i+1)*common.L1CoordinatorTxBytesLen]
878 var signature []byte
879 v := bytesL1Coordinator[0]
880 s := bytesL1Coordinator[1:33]
881 r := bytesL1Coordinator[33:65]
882 signature = append(signature, r[:]...)
883 signature = append(signature, s[:]...)
884 signature = append(signature, v)
885 l1Tx, err := common.L1CoordinatorTxFromBytes(bytesL1Coordinator, c.chainID, c.address)
886 if err != nil {
887 return nil, nil, tracerr.Wrap(err)
888 }
889 rollupForgeBatchArgs.L1CoordinatorTxs = append(rollupForgeBatchArgs.L1CoordinatorTxs, *l1Tx)
890 rollupForgeBatchArgs.L1CoordinatorTxsAuths = append(rollupForgeBatchArgs.L1CoordinatorTxsAuths, signature)
891 }
892 lenFeeIdxCoordinatorBytes := int(nLevels / 8) //nolint:gomnd
893 numFeeIdxCoordinator := len(aux.FeeIdxCoordinator) / lenFeeIdxCoordinatorBytes
894 for i := 0; i < numFeeIdxCoordinator; i++ {
895 var paddedFeeIdx [6]byte
896 // TODO: This check is not necessary: the first case will always work. Test it before removing the if.
897 if lenFeeIdxCoordinatorBytes < common.IdxBytesLen {
898 copy(paddedFeeIdx[6-lenFeeIdxCoordinatorBytes:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
899 } else {
900 copy(paddedFeeIdx[:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
901 }
902 feeIdxCoordinator, err := common.IdxFromBytes(paddedFeeIdx[:])
903 if err != nil {
904 return nil, nil, tracerr.Wrap(err)
905 }
906 if feeIdxCoordinator != common.Idx(0) {
907 rollupForgeBatchArgs.FeeIdxCoordinator = append(rollupForgeBatchArgs.FeeIdxCoordinator, feeIdxCoordinator)
908 }
909 }
910 return &rollupForgeBatchArgs, &sender, nil
911}