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