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