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