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