hermez-node/eth/rollup.go
eth/rollup.goRaw
1package eth
2
3import (
4 "context"
5 "fmt"
6 "math/big"
7 "strings"
8
9 "github.com/ethereum/go-ethereum"
10 "github.com/ethereum/go-ethereum/accounts/abi"
11 "github.com/ethereum/go-ethereum/accounts/abi/bind"
12 ethCommon "github.com/ethereum/go-ethereum/common"
13 "github.com/ethereum/go-ethereum/core/types"
14 "github.com/ethereum/go-ethereum/crypto"
15 "github.com/ethereum/go-ethereum/ethclient"
16 "github.com/hermeznetwork/hermez-node/common"
17 ERC777 "github.com/hermeznetwork/hermez-node/eth/contracts/erc777"
18 Hermez "github.com/hermeznetwork/hermez-node/eth/contracts/hermez"
19 "github.com/hermeznetwork/hermez-node/log"
20 "github.com/iden3/go-iden3-crypto/babyjub"
21 "golang.org/x/crypto/sha3"
22)
23
24const (
25 // RollupConstMaxFeeIdxCoordinator is the maximum number of tokens the
26 // coordinator can use to collect fees (determines the number of tokens
27 // that the coordinator can collect fees from). This value is
28 // determined by the circuit.
29 RollupConstMaxFeeIdxCoordinator = 64
30 // RollupConstReservedIDx First 256 indexes reserved, first user index will be the 256
31 RollupConstReservedIDx = 255
32 // RollupConstExitIDx IDX 1 is reserved for exits
33 RollupConstExitIDx = 1
34 // RollupConstLimitLoadAmount Max load amount allowed (loadAmount: L1 --> L2)
35 RollupConstLimitLoadAmount = (1 << 128)
36 // RollupConstLimitL2TransferAmount Max amount allowed (amount L2 --> L2)
37 RollupConstLimitL2TransferAmount = (1 << 192)
38 // RollupConstLimitTokens Max number of tokens allowed to be registered inside the rollup
39 RollupConstLimitTokens = (1 << 32)
40 // RollupConstL1CoordinatorTotalBytes [4 bytes] token + [32 bytes] babyjub + [65 bytes] compressedSignature
41 RollupConstL1CoordinatorTotalBytes = 101
42 // RollupConstL1UserTotalBytes [20 bytes] fromEthAddr + [32 bytes] fromBjj-compressed + [6 bytes] fromIdx +
43 // [2 bytes] loadAmountFloat16 + [2 bytes] amountFloat16 + [4 bytes] tokenId + [6 bytes] toIdx
44 RollupConstL1UserTotalBytes = 72
45 // RollupConstMaxL1UserTx Maximum L1-user transactions allowed to be queued in a batch
46 RollupConstMaxL1UserTx = 128
47 // RollupConstMaxL1Tx Maximum L1 transactions allowed to be queued in a batch
48 RollupConstMaxL1Tx = 256
49 // RollupConstInputSHAConstantBytes [6 bytes] lastIdx + [6 bytes] newLastIdx + [32 bytes] stateRoot + [32 bytes] newStRoot + [32 bytes] newExitRoot +
50 // [_MAX_L1_TX * _L1_USER_TOTALBYTES bytes] l1TxsData + totalL2TxsDataLength + feeIdxCoordinatorLength + [2 bytes] chainID =
51 // 18542 bytes + totalL2TxsDataLength + feeIdxCoordinatorLength
52 RollupConstInputSHAConstantBytes = 18542
53 // RollupConstNumBuckets Number of buckets
54 RollupConstNumBuckets = 5
55 // RollupConstMaxWithdrawalDelay max withdrawal delay in seconds
56 RollupConstMaxWithdrawalDelay = 2 * 7 * 24 * 60 * 60
57 // RollupConstExchangeMultiplier exchange multiplier
58 RollupConstExchangeMultiplier = 1e14
59 // LenVerifiers number of Rollup Smart Contract Verifiers
60 LenVerifiers = 1
61)
62
63var (
64 // RollupConstEthAddressInternalOnly This ethereum address is used internally for rollup accounts that don't have ethereum address, only Babyjubjub
65 // This non-ethereum accounts can be created by the coordinator and allow users to have a rollup
66 // account without needing an ethereum address
67 RollupConstEthAddressInternalOnly = ethCommon.HexToAddress("0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF")
68 // RollupConstRfield Modulus zkSNARK
69 RollupConstRfield, _ = new(big.Int).SetString(
70 "21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
71
72 // RollupConstERC1820 ERC1820Registry address
73 RollupConstERC1820 = ethCommon.HexToAddress("0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24")
74
75 // ERC777 tokens signatures
76
77 // RollupConstRecipientInterfaceHash ERC777 recipient interface hash
78 RollupConstRecipientInterfaceHash = crypto.Keccak256([]byte("ERC777TokensRecipient"))
79 // RollupConstPerformL1UserTxSignature the signature of the function that can be called thru an ERC777 `send`
80 RollupConstPerformL1UserTxSignature = crypto.Keccak256([]byte("addL1Transaction(uint256,uint48,uint16,uint16,uint32,uint48)"))
81 // RollupConstAddTokenSignature the signature of the function that can be called thru an ERC777 `send`
82 RollupConstAddTokenSignature = crypto.Keccak256([]byte("addToken(address)"))
83 // RollupConstSendSignature ERC777 Signature
84 RollupConstSendSignature = crypto.Keccak256([]byte("send(address,uint256,bytes)"))
85 // RollupConstERC777Granularity ERC777 Signature
86 RollupConstERC777Granularity = crypto.Keccak256([]byte("granularity()"))
87 // RollupConstWithdrawalDelayerDeposit This constant are used to deposit tokens from ERC77 tokens into withdrawal delayer
88 RollupConstWithdrawalDelayerDeposit = crypto.Keccak256([]byte("deposit(address,address,uint192)"))
89
90 // ERC20 signature
91
92 // RollupConstTransferSignature This constant is used in the _safeTransfer internal method in order to safe GAS.
93 RollupConstTransferSignature = crypto.Keccak256([]byte("transfer(address,uint256)"))
94 // RollupConstTransferFromSignature This constant is used in the _safeTransfer internal method in order to safe GAS.
95 RollupConstTransferFromSignature = crypto.Keccak256([]byte("transferFrom(address,address,uint256)"))
96 // RollupConstApproveSignature This constant is used in the _safeTransfer internal method in order to safe GAS.
97 RollupConstApproveSignature = crypto.Keccak256([]byte("approve(address,uint256)"))
98 // RollupConstERC20Signature ERC20 decimals signature
99 RollupConstERC20Signature = crypto.Keccak256([]byte("decimals()"))
100)
101
102// RollupPublicConstants are the constants of the Rollup Smart Contract
103type RollupPublicConstants struct {
104 AbsoluteMaxL1L2BatchTimeout int64
105 TokenHEZ ethCommon.Address
106 Verifiers []RollupVerifierStruct
107 HermezAuctionContract ethCommon.Address
108 HermezGovernanceDAOAddress ethCommon.Address
109 SafetyAddress ethCommon.Address
110 WithdrawDelayerContract ethCommon.Address
111}
112
113// RollupVariables are the variables of the Rollup Smart Contract
114type RollupVariables struct {
115 FeeAddToken *big.Int
116 ForgeL1L2BatchTimeout int64
117 WithdrawalDelay uint64
118}
119
120// QueueStruct is the queue of L1Txs for a batch
121type QueueStruct struct {
122 L1TxQueue []common.L1Tx
123 TotalL1TxFee *big.Int
124}
125
126// NewQueueStruct creates a new clear QueueStruct.
127func NewQueueStruct() *QueueStruct {
128 return &QueueStruct{
129 L1TxQueue: make([]common.L1Tx, 0),
130 TotalL1TxFee: big.NewInt(0),
131 }
132}
133
134// RollupVerifierStruct is the information about verifiers of the Rollup Smart Contract
135type RollupVerifierStruct struct {
136 MaxTx int64
137 NLevels int64
138}
139
140// RollupState represents the state of the Rollup in the Smart Contract
141type RollupState struct {
142 StateRoot *big.Int
143 ExitRoots []*big.Int
144 ExitNullifierMap map[[256 / 8]byte]bool
145 TokenList []ethCommon.Address
146 TokenMap map[ethCommon.Address]bool
147 MapL1TxQueue map[int64]*QueueStruct
148 LastL1L2Batch int64
149 CurrentToForgeL1TxsNum int64
150 LastToForgeL1TxsNum int64
151 CurrentIdx int64
152}
153
154// RollupEventL1UserTx is an event of the Rollup Smart Contract
155type RollupEventL1UserTx struct {
156 // ToForgeL1TxsNum int64 // QueueIndex *big.Int
157 // Position int // TransactionIndex *big.Int
158 L1UserTx common.L1Tx
159}
160
161// RollupEventL1UserTxAux is an event of the Rollup Smart Contract
162type RollupEventL1UserTxAux struct {
163 ToForgeL1TxsNum uint64 // QueueIndex *big.Int
164 Position uint8 // TransactionIndex *big.Int
165 L1UserTx []byte
166}
167
168// RollupEventAddToken is an event of the Rollup Smart Contract
169type RollupEventAddToken struct {
170 TokenAddress ethCommon.Address
171 TokenID uint32
172}
173
174// RollupEventForgeBatch is an event of the Rollup Smart Contract
175type RollupEventForgeBatch struct {
176 BatchNum int64
177 // Sender ethCommon.Address
178 EthTxHash ethCommon.Hash
179}
180
181// RollupEventUpdateForgeL1L2BatchTimeout is an event of the Rollup Smart Contract
182type RollupEventUpdateForgeL1L2BatchTimeout struct {
183 NewForgeL1L2BatchTimeout int64
184}
185
186// RollupEventUpdateFeeAddToken is an event of the Rollup Smart Contract
187type RollupEventUpdateFeeAddToken struct {
188 NewFeeAddToken *big.Int
189}
190
191// RollupEventWithdrawEvent is an event of the Rollup Smart Contract
192type RollupEventWithdrawEvent struct {
193 Idx uint64
194 NumExitRoot uint64
195 InstantWithdraw bool
196}
197
198// RollupEvents is the list of events in a block of the Rollup Smart Contract
199type RollupEvents struct {
200 L1UserTx []RollupEventL1UserTx
201 AddToken []RollupEventAddToken
202 ForgeBatch []RollupEventForgeBatch
203 UpdateForgeL1L2BatchTimeout []RollupEventUpdateForgeL1L2BatchTimeout
204 UpdateFeeAddToken []RollupEventUpdateFeeAddToken
205 WithdrawEvent []RollupEventWithdrawEvent
206}
207
208// NewRollupEvents creates an empty RollupEvents with the slices initialized.
209func NewRollupEvents() RollupEvents {
210 return RollupEvents{
211 L1UserTx: make([]RollupEventL1UserTx, 0),
212 AddToken: make([]RollupEventAddToken, 0),
213 ForgeBatch: make([]RollupEventForgeBatch, 0),
214 UpdateForgeL1L2BatchTimeout: make([]RollupEventUpdateForgeL1L2BatchTimeout, 0),
215 UpdateFeeAddToken: make([]RollupEventUpdateFeeAddToken, 0),
216 WithdrawEvent: make([]RollupEventWithdrawEvent, 0),
217 }
218}
219
220// RollupForgeBatchArgs are the arguments to the ForgeBatch function in the Rollup Smart Contract
221type RollupForgeBatchArgs struct {
222 NewLastIdx int64
223 NewStRoot *big.Int
224 NewExitRoot *big.Int
225 L1CoordinatorTxs []common.L1Tx
226 L1CoordinatorTxsAuths [][]byte // Authorization for accountCreations for each L1CoordinatorTx
227 L2TxsData []common.L2Tx
228 FeeIdxCoordinator []common.Idx
229 // Circuit selector
230 VerifierIdx uint8
231 L1Batch bool
232 ProofA [2]*big.Int
233 ProofB [2][2]*big.Int
234 ProofC [2]*big.Int
235}
236
237// RollupForgeBatchArgsAux are the arguments to the ForgeBatch function in the Rollup Smart Contract
238type RollupForgeBatchArgsAux struct {
239 NewLastIdx *big.Int
240 NewStRoot *big.Int
241 NewExitRoot *big.Int
242 EncodedL1CoordinatorTx []byte
243 L2TxsData []byte
244 FeeIdxCoordinator []byte
245 // Circuit selector
246 VerifierIdx uint8
247 L1Batch bool
248 ProofA [2]*big.Int
249 ProofB [2][2]*big.Int
250 ProofC [2]*big.Int
251}
252
253// RollupInterface is the inteface to to Rollup Smart Contract
254type RollupInterface interface {
255 //
256 // Smart Contract Methods
257 //
258
259 // Public Functions
260
261 RollupForgeBatch(*RollupForgeBatchArgs) (*types.Transaction, error)
262 RollupAddToken(tokenAddress ethCommon.Address, feeAddToken *big.Int) (*types.Transaction, error)
263
264 RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error)
265 RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error)
266
267 RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error)
268 RollupL1UserTxERC777(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error)
269
270 // Governance Public Functions
271 RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (*types.Transaction, error)
272 RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (*types.Transaction, error)
273
274 // Viewers
275 RollupRegisterTokensCount() (*big.Int, error)
276
277 //
278 // Smart Contract Status
279 //
280
281 RollupConstants() (*RollupPublicConstants, error)
282 RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error)
283 RollupForgeBatchArgs(ethCommon.Hash) (*RollupForgeBatchArgs, *ethCommon.Address, error)
284}
285
286//
287// Implementation
288//
289
290// RollupClient is the implementation of the interface to the Rollup Smart Contract in ethereum.
291type RollupClient struct {
292 client *EthereumClient
293 address ethCommon.Address
294 tokenHEZAddress ethCommon.Address
295 hermez *Hermez.Hermez
296 contractAbi abi.ABI
297}
298
299// NewRollupClient creates a new RollupClient
300func NewRollupClient(client *EthereumClient, address ethCommon.Address, tokenHEZAddress ethCommon.Address) (*RollupClient, error) {
301 contractAbi, err := abi.JSON(strings.NewReader(string(Hermez.HermezABI)))
302 if err != nil {
303 return nil, err
304 }
305 hermez, err := Hermez.NewHermez(address, client.Client())
306 if err != nil {
307 return nil, err
308 }
309 return &RollupClient{
310 client: client,
311 address: address,
312 tokenHEZAddress: tokenHEZAddress,
313 hermez: hermez,
314 contractAbi: contractAbi,
315 }, nil
316}
317
318// RollupForgeBatch is the interface to call the smart contract function
319func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (tx *types.Transaction, err error) {
320 if tx, err = c.client.CallAuth(
321 1000000, //nolint:gomnd
322 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
323 rollupConst, err := c.RollupConstants()
324 if err != nil {
325 return nil, err
326 }
327 nLevels := rollupConst.Verifiers[args.VerifierIdx].NLevels
328 lenBytes := nLevels / 8 //nolint:gomnd
329 newLastIdx := big.NewInt(int64(args.NewLastIdx))
330 var l1CoordinatorBytes []byte
331 for i := 0; i < len(args.L1CoordinatorTxs); i++ {
332 l1 := args.L1CoordinatorTxs[i]
333 bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i])
334 if err != nil {
335 return nil, err
336 }
337 l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...)
338 }
339 var l2DataBytes []byte
340 for i := 0; i < len(args.L2TxsData); i++ {
341 l2 := args.L2TxsData[i]
342 bytesl2, err := l2.Bytes(int(nLevels))
343 if err != nil {
344 return nil, err
345 }
346 l2DataBytes = append(l2DataBytes, bytesl2[:]...)
347 }
348 var feeIdxCoordinator []byte
349 if len(args.FeeIdxCoordinator) > RollupConstMaxFeeIdxCoordinator {
350 return nil, fmt.Errorf("len(args.FeeIdxCoordinator) > %v",
351 RollupConstMaxFeeIdxCoordinator)
352 }
353 for i := 0; i < RollupConstMaxFeeIdxCoordinator; i++ {
354 feeIdx := common.Idx(0)
355 if i < len(args.FeeIdxCoordinator) {
356 feeIdx = args.FeeIdxCoordinator[i]
357 }
358 bytesFeeIdx, err := feeIdx.Bytes()
359 if err != nil {
360 return nil, err
361 }
362 feeIdxCoordinator = append(feeIdxCoordinator, bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...)
363 }
364 return c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, l1CoordinatorBytes, l2DataBytes, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, args.ProofA, args.ProofB, args.ProofC)
365 },
366 ); err != nil {
367 return nil, fmt.Errorf("Failed forge batch: %w", err)
368 }
369 return tx, nil
370}
371
372// RollupAddToken is the interface to call the smart contract function.
373// `feeAddToken` is the amount of HEZ tokens that will be paid to add the
374// token. `feeAddToken` must match the public value of the smart contract.
375func (c *RollupClient) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken *big.Int) (tx *types.Transaction, err error) {
376 if tx, err = c.client.CallAuth(
377 0,
378 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
379 tokens, err := ERC777.NewERC777(c.tokenHEZAddress, ec)
380 if err != nil {
381 return nil, err
382 }
383 addTokenFnSignature := []byte("addToken(address)")
384 hash := sha3.NewLegacyKeccak256()
385 _, err = hash.Write(addTokenFnSignature)
386 if err != nil {
387 return nil, err
388 }
389 methodID := hash.Sum(nil)[:4]
390 var data []byte
391 data = append(data, methodID...)
392 paddedAddress := ethCommon.LeftPadBytes(tokenAddress.Bytes(), 32)
393 data = append(data, paddedAddress[:]...)
394 return tokens.Send(auth, c.address, feeAddToken, data)
395 },
396 ); err != nil {
397 return nil, fmt.Errorf("Failed add Token %w", err)
398 }
399 return tx, nil
400}
401
402// RollupWithdrawMerkleProof is the interface to call the smart contract function
403func (c *RollupClient) RollupWithdrawMerkleProof(fromBJJ *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) {
404 if tx, err = c.client.CallAuth(
405 0,
406 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
407 hermez, err := Hermez.NewHermez(c.address, ec)
408 if err != nil {
409 return nil, err
410 }
411 pkCompL := fromBJJ.Compress()
412 pkCompB := common.SwapEndianness(pkCompL[:])
413 babyPubKey := new(big.Int).SetBytes(pkCompB)
414 numExitRootB := big.NewInt(numExitRoot)
415 idxBig := big.NewInt(idx)
416 return hermez.WithdrawMerkleProof(auth, tokenID, amount, babyPubKey, numExitRootB, siblings, idxBig, instantWithdraw)
417 },
418 ); err != nil {
419 return nil, fmt.Errorf("Failed update WithdrawMerkleProof: %w", err)
420 }
421 return tx, nil
422}
423
424// RollupWithdrawCircuit is the interface to call the smart contract function
425func (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) {
426 log.Error("TODO")
427 return nil, errTODO
428}
429
430// RollupL1UserTxERC20ETH is the interface to call the smart contract function
431func (c *RollupClient) RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (tx *types.Transaction, err error) {
432 if tx, err = c.client.CallAuth(
433 0,
434 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
435 hermez, err := Hermez.NewHermez(c.address, ec)
436 if err != nil {
437 return nil, err
438 }
439 pkCompL := fromBJJ.Compress()
440 pkCompB := common.SwapEndianness(pkCompL[:])
441 babyPubKey := new(big.Int).SetBytes(pkCompB)
442 fromIdxBig := big.NewInt(fromIdx)
443 toIdxBig := big.NewInt(toIdx)
444 tokenIDBig := uint32(tokenID)
445 loadAmountF, err := common.NewFloat16(loadAmount)
446 if err != nil {
447 return nil, err
448 }
449 amountF, err := common.NewFloat16(amount)
450 if err != nil {
451 return nil, err
452 }
453 if tokenID == 0 {
454 auth.Value = loadAmount
455 }
456 return hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(loadAmountF), uint16(amountF), tokenIDBig, toIdxBig)
457 },
458 ); err != nil {
459 return nil, fmt.Errorf("Failed add L1 Tx ERC20/ETH: %w", err)
460 }
461 return tx, nil
462}
463
464// RollupL1UserTxERC777 is the interface to call the smart contract function
465func (c *RollupClient) RollupL1UserTxERC777(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (tx *types.Transaction, err error) {
466 if tx, err = c.client.CallAuth(
467 0,
468 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
469 tokens, err := ERC777.NewERC777(c.tokenHEZAddress, ec)
470 if err != nil {
471 return nil, err
472 }
473 addL1TxFnSignature := []byte("addL1Transaction(uint256,uint48,uint16,uint16,uint32,uint48)")
474 hash := sha3.NewLegacyKeccak256()
475 _, err = hash.Write(addL1TxFnSignature)
476 if err != nil {
477 return nil, err
478 }
479 methodID := hash.Sum(nil)[:4]
480 pkCompL := fromBJJ.Compress()
481 pkCompB := common.SwapEndianness(pkCompL[:])
482 paddedAddress := ethCommon.LeftPadBytes(pkCompB, 32)
483 fromIdxB, err := common.Idx(fromIdx).Bytes()
484 if err != nil {
485 return nil, err
486 }
487 paddedFromIdx := ethCommon.LeftPadBytes(fromIdxB[:], 32)
488 loadAmountF, err := common.NewFloat16(loadAmount)
489 if err != nil {
490 return nil, err
491 }
492 paddedLoadAmount := ethCommon.LeftPadBytes(loadAmountF.Bytes(), 32)
493 amountF, err := common.NewFloat16(amount)
494 if err != nil {
495 return nil, err
496 }
497 paddedAmount := ethCommon.LeftPadBytes(amountF.Bytes(), 32)
498 tokenIDB := common.TokenID(tokenID).Bytes()
499 paddedTokenID := ethCommon.LeftPadBytes(tokenIDB, 32)
500 toIdxB, err := common.Idx(toIdx).Bytes()
501 if err != nil {
502 return nil, err
503 }
504 paddedToIdx := ethCommon.LeftPadBytes(toIdxB[:], 32)
505 var data []byte
506 data = append(data, methodID...)
507 data = append(data, paddedAddress[:]...)
508 data = append(data, paddedFromIdx[:]...)
509 data = append(data, paddedLoadAmount[:]...)
510 data = append(data, paddedAmount[:]...)
511 data = append(data, paddedTokenID[:]...)
512 data = append(data, paddedToIdx[:]...)
513 return tokens.Send(auth, c.address, loadAmount, data)
514 },
515 ); err != nil {
516 return nil, fmt.Errorf("Failed add L1 Tx ERC777: %w", err)
517 }
518 return tx, nil
519}
520
521// RollupRegisterTokensCount is the interface to call the smart contract function
522func (c *RollupClient) RollupRegisterTokensCount() (*big.Int, error) {
523 var registerTokensCount *big.Int
524 if err := c.client.Call(func(ec *ethclient.Client) error {
525 hermez, err := Hermez.NewHermez(c.address, ec)
526 if err != nil {
527 return err
528 }
529 registerTokensCount, err = hermez.RegisterTokensCount(nil)
530 return err
531 }); err != nil {
532 return nil, err
533 }
534 return registerTokensCount, nil
535}
536
537// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
538func (c *RollupClient) RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (tx *types.Transaction, err error) {
539 if tx, err = c.client.CallAuth(
540 0,
541 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
542 hermez, err := Hermez.NewHermez(c.address, ec)
543 if err != nil {
544 return nil, err
545 }
546 return hermez.UpdateForgeL1L2BatchTimeout(auth, uint8(newForgeL1L2BatchTimeout))
547 },
548 ); err != nil {
549 return nil, fmt.Errorf("Failed update ForgeL1L2BatchTimeout: %w", err)
550 }
551 return tx, nil
552}
553
554// RollupUpdateFeeAddToken is the interface to call the smart contract function
555func (c *RollupClient) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
556 if tx, err = c.client.CallAuth(
557 0,
558 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
559 hermez, err := Hermez.NewHermez(c.address, ec)
560 if err != nil {
561 return nil, err
562 }
563 return hermez.UpdateFeeAddToken(auth, newFeeAddToken)
564 },
565 ); err != nil {
566 return nil, fmt.Errorf("Failed update FeeAddToken: %w", err)
567 }
568 return tx, nil
569}
570
571// RollupConstants returns the Constants of the Rollup Smart Contract
572func (c *RollupClient) RollupConstants() (rollupConstants *RollupPublicConstants, err error) {
573 rollupConstants = new(RollupPublicConstants)
574 if err := c.client.Call(func(ec *ethclient.Client) error {
575 absoluteMaxL1L2BatchTimeout, err := c.hermez.ABSOLUTEMAXL1L2BATCHTIMEOUT(nil)
576 if err != nil {
577 return err
578 }
579 rollupConstants.AbsoluteMaxL1L2BatchTimeout = int64(absoluteMaxL1L2BatchTimeout)
580 rollupConstants.TokenHEZ, err = c.hermez.TokenHEZ(nil)
581 if err != nil {
582 return err
583 }
584 for i := int64(0); i < int64(LenVerifiers); i++ {
585 var newRollupVerifier RollupVerifierStruct
586 rollupVerifier, err := c.hermez.RollupVerifiers(nil, big.NewInt(i))
587 if err != nil {
588 return err
589 }
590 newRollupVerifier.MaxTx = rollupVerifier.MaxTx.Int64()
591 newRollupVerifier.NLevels = rollupVerifier.NLevels.Int64()
592 rollupConstants.Verifiers = append(rollupConstants.Verifiers, newRollupVerifier)
593 }
594 rollupConstants.HermezAuctionContract, err = c.hermez.HermezAuctionContract(nil)
595 if err != nil {
596 return err
597 }
598 rollupConstants.HermezGovernanceDAOAddress, err = c.hermez.HermezGovernanceDAOAddress(nil)
599 if err != nil {
600 return err
601 }
602 rollupConstants.SafetyAddress, err = c.hermez.SafetyAddress(nil)
603 if err != nil {
604 return err
605 }
606 rollupConstants.WithdrawDelayerContract, err = c.hermez.WithdrawDelayerContract(nil)
607 return err
608 }); err != nil {
609 return nil, err
610 }
611 return rollupConstants, nil
612}
613
614var (
615 logHermezL1UserTxEvent = crypto.Keccak256Hash([]byte("L1UserTxEvent(uint64,uint8,bytes)"))
616 logHermezAddToken = crypto.Keccak256Hash([]byte("AddToken(address,uint32)"))
617 logHermezForgeBatch = crypto.Keccak256Hash([]byte("ForgeBatch(uint64)"))
618 logHermezUpdateForgeL1L2BatchTimeout = crypto.Keccak256Hash([]byte("UpdateForgeL1L2BatchTimeout(uint8)"))
619 logHermezUpdateFeeAddToken = crypto.Keccak256Hash([]byte("UpdateFeeAddToken(uint256)"))
620 logHermezWithdrawEvent = crypto.Keccak256Hash([]byte("WithdrawEvent(uint48,uint48,bool)"))
621)
622
623// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
624func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) {
625 var rollupEvents RollupEvents
626 var blockHash ethCommon.Hash
627
628 query := ethereum.FilterQuery{
629 FromBlock: big.NewInt(blockNum),
630 ToBlock: big.NewInt(blockNum),
631 Addresses: []ethCommon.Address{
632 c.address,
633 },
634 BlockHash: nil,
635 Topics: [][]ethCommon.Hash{},
636 }
637 logs, err := c.client.client.FilterLogs(context.Background(), query)
638 if err != nil {
639 return nil, nil, err
640 }
641 if len(logs) > 0 {
642 blockHash = logs[0].BlockHash
643 }
644 for _, vLog := range logs {
645 if vLog.BlockHash != blockHash {
646 return nil, nil, ErrBlockHashMismatchEvent
647 }
648 switch vLog.Topics[0] {
649 case logHermezL1UserTxEvent:
650 var L1UserTxAux RollupEventL1UserTxAux
651 var L1UserTx RollupEventL1UserTx
652 err := c.contractAbi.Unpack(&L1UserTxAux, "L1UserTxEvent", vLog.Data)
653 if err != nil {
654 return nil, nil, err
655 }
656 L1Tx, err := common.L1UserTxFromBytes(L1UserTxAux.L1UserTx)
657 if err != nil {
658 return nil, nil, err
659 }
660 toForgeL1TxsNum := new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
661 L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
662 L1Tx.Position = int(new(big.Int).SetBytes(vLog.Topics[2][:]).Int64())
663 L1Tx.UserOrigin = true
664 L1UserTx.L1UserTx = *L1Tx
665 rollupEvents.L1UserTx = append(rollupEvents.L1UserTx, L1UserTx)
666 case logHermezAddToken:
667 var addToken RollupEventAddToken
668 err := c.contractAbi.Unpack(&addToken, "AddToken", vLog.Data)
669 if err != nil {
670 return nil, nil, err
671 }
672 addToken.TokenAddress = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
673 rollupEvents.AddToken = append(rollupEvents.AddToken, addToken)
674 case logHermezForgeBatch:
675 var forgeBatch RollupEventForgeBatch
676 forgeBatch.BatchNum = new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
677 forgeBatch.EthTxHash = vLog.TxHash
678 // forgeBatch.Sender = vLog.Address
679 rollupEvents.ForgeBatch = append(rollupEvents.ForgeBatch, forgeBatch)
680 case logHermezUpdateForgeL1L2BatchTimeout:
681 var updateForgeL1L2BatchTimeout struct {
682 NewForgeL1L2BatchTimeout uint8
683 }
684 err := c.contractAbi.Unpack(&updateForgeL1L2BatchTimeout, "UpdateForgeL1L2BatchTimeout", vLog.Data)
685 if err != nil {
686 return nil, nil, err
687 }
688 rollupEvents.UpdateForgeL1L2BatchTimeout = append(rollupEvents.UpdateForgeL1L2BatchTimeout,
689 RollupEventUpdateForgeL1L2BatchTimeout{
690 NewForgeL1L2BatchTimeout: int64(updateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout),
691 })
692 case logHermezUpdateFeeAddToken:
693 var updateFeeAddToken RollupEventUpdateFeeAddToken
694 err := c.contractAbi.Unpack(&updateFeeAddToken, "UpdateFeeAddToken", vLog.Data)
695 if err != nil {
696 return nil, nil, err
697 }
698 rollupEvents.UpdateFeeAddToken = append(rollupEvents.UpdateFeeAddToken, updateFeeAddToken)
699 case logHermezWithdrawEvent:
700 var withdraw RollupEventWithdrawEvent
701 withdraw.Idx = new(big.Int).SetBytes(vLog.Topics[1][:]).Uint64()
702 withdraw.NumExitRoot = new(big.Int).SetBytes(vLog.Topics[2][:]).Uint64()
703 instantWithdraw := new(big.Int).SetBytes(vLog.Topics[3][:]).Uint64()
704 if instantWithdraw == 1 {
705 withdraw.InstantWithdraw = true
706 }
707 rollupEvents.WithdrawEvent = append(rollupEvents.WithdrawEvent, withdraw)
708 }
709 }
710 return &rollupEvents, &blockHash, nil
711}
712
713// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the
714// Rollup Smart Contract in the given transaction, and the sender address.
715func (c *RollupClient) RollupForgeBatchArgs(ethTxHash ethCommon.Hash) (*RollupForgeBatchArgs, *ethCommon.Address, error) {
716 tx, _, err := c.client.client.TransactionByHash(context.Background(), ethTxHash)
717 if err != nil {
718 return nil, nil, err
719 }
720 txData := tx.Data()
721 method, err := c.contractAbi.MethodById(txData[:4])
722 if err != nil {
723 return nil, nil, err
724 }
725 receipt, err := c.client.client.TransactionReceipt(context.Background(), ethTxHash)
726 if err != nil {
727 return nil, nil, err
728 }
729 sender, err := c.client.client.TransactionSender(context.Background(), tx, receipt.Logs[0].BlockHash, receipt.Logs[0].Index)
730 if err != nil {
731 return nil, nil, err
732 }
733 var aux RollupForgeBatchArgsAux
734 if err := method.Inputs.Unpack(&aux, txData[4:]); err != nil {
735 return nil, nil, err
736 }
737 rollupForgeBatchArgs := RollupForgeBatchArgs{
738 L1Batch: aux.L1Batch,
739 NewExitRoot: aux.NewExitRoot,
740 NewLastIdx: aux.NewLastIdx.Int64(),
741 NewStRoot: aux.NewStRoot,
742 ProofA: aux.ProofA,
743 ProofB: aux.ProofB,
744 ProofC: aux.ProofC,
745 VerifierIdx: aux.VerifierIdx,
746 L1CoordinatorTxs: []common.L1Tx{},
747 L1CoordinatorTxsAuths: [][]byte{},
748 L2TxsData: []common.L2Tx{},
749 FeeIdxCoordinator: []common.Idx{},
750 }
751 numTxsL1 := len(aux.EncodedL1CoordinatorTx) / common.L1CoordinatorTxBytesLen
752 for i := 0; i < numTxsL1; i++ {
753 bytesL1Coordinator := aux.EncodedL1CoordinatorTx[i*common.L1CoordinatorTxBytesLen : (i+1)*common.L1CoordinatorTxBytesLen]
754 var signature []byte
755 v := bytesL1Coordinator[0]
756 s := bytesL1Coordinator[1:33]
757 r := bytesL1Coordinator[33:65]
758 signature = append(signature, r[:]...)
759 signature = append(signature, s[:]...)
760 signature = append(signature, v)
761 l1Tx, err := common.L1CoordinatorTxFromBytes(bytesL1Coordinator)
762 if err != nil {
763 return nil, nil, err
764 }
765 rollupForgeBatchArgs.L1CoordinatorTxs = append(rollupForgeBatchArgs.L1CoordinatorTxs, *l1Tx)
766 rollupForgeBatchArgs.L1CoordinatorTxsAuths = append(rollupForgeBatchArgs.L1CoordinatorTxsAuths, signature)
767 }
768 rollupConsts, err := c.RollupConstants()
769 if err != nil {
770 return nil, nil, err
771 }
772 nLevels := rollupConsts.Verifiers[rollupForgeBatchArgs.VerifierIdx].NLevels
773 lenL2TxsBytes := int((nLevels/8)*2 + 2 + 1)
774 numTxsL2 := len(aux.L2TxsData) / lenL2TxsBytes
775 for i := 0; i < numTxsL2; i++ {
776 l2Tx, err := common.L2TxFromBytes(aux.L2TxsData[i*lenL2TxsBytes:(i+1)*lenL2TxsBytes], int(nLevels))
777 if err != nil {
778 return nil, nil, err
779 }
780 rollupForgeBatchArgs.L2TxsData = append(rollupForgeBatchArgs.L2TxsData, *l2Tx)
781 }
782 lenFeeIdxCoordinatorBytes := int(nLevels / 8) //nolint:gomnd
783 numFeeIdxCoordinator := len(aux.FeeIdxCoordinator) / lenFeeIdxCoordinatorBytes
784 for i := 0; i < numFeeIdxCoordinator; i++ {
785 var paddedFeeIdx [6]byte
786 // TODO: This check is not necessary: the first case will always work. Test it before removing the if.
787 if lenFeeIdxCoordinatorBytes < common.IdxBytesLen {
788 copy(paddedFeeIdx[6-lenFeeIdxCoordinatorBytes:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
789 } else {
790 copy(paddedFeeIdx[:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
791 }
792 feeIdxCoordinator, err := common.IdxFromBytes(paddedFeeIdx[:])
793 if err != nil {
794 return nil, nil, err
795 }
796 if feeIdxCoordinator != common.Idx(0) {
797 rollupForgeBatchArgs.FeeIdxCoordinator = append(rollupForgeBatchArgs.FeeIdxCoordinator, feeIdxCoordinator)
798 }
799 }
800 return &rollupForgeBatchArgs, &sender, nil
801}