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