hermez-node/test/ethclient.go
test/ethclient.goRaw
1package test
2
3import (
4 "context"
5 "encoding/binary"
6 "encoding/json"
7 "fmt"
8 "math/big"
9 "reflect"
10 "sync"
11 "time"
12
13 "github.com/ethereum/go-ethereum"
14 ethCommon "github.com/ethereum/go-ethereum/common"
15 "github.com/ethereum/go-ethereum/core/types"
16 "github.com/hermeznetwork/hermez-node/common"
17 "github.com/hermeznetwork/hermez-node/eth"
18 "github.com/hermeznetwork/hermez-node/log"
19 "github.com/hermeznetwork/tracerr"
20 "github.com/iden3/go-iden3-crypto/babyjub"
21 "github.com/mitchellh/copystructure"
22)
23
24func init() {
25 copystructure.Copiers[reflect.TypeOf(big.Int{})] =
26 func(raw interface{}) (interface{}, error) {
27 in := raw.(big.Int)
28 out := new(big.Int).Set(&in)
29 return *out, nil
30 }
31}
32
33// WDelayerBlock stores all the data related to the WDelayer SC from an ethereum block
34type WDelayerBlock struct {
35 // State eth.WDelayerState // TODO
36 Vars common.WDelayerVariables
37 Events eth.WDelayerEvents
38 Txs map[ethCommon.Hash]*types.Transaction
39 Constants *common.WDelayerConstants
40 Eth *EthereumBlock
41}
42
43func (w *WDelayerBlock) addTransaction(tx *types.Transaction) *types.Transaction {
44 txHash := tx.Hash()
45 w.Txs[txHash] = tx
46 return tx
47}
48
49func (w *WDelayerBlock) deposit(txHash ethCommon.Hash, owner, token ethCommon.Address, amount *big.Int) {
50 w.Events.Deposit = append(w.Events.Deposit, eth.WDelayerEventDeposit{
51 Owner: owner,
52 Token: token,
53 Amount: amount,
54 DepositTimestamp: uint64(w.Eth.Time),
55 TxHash: txHash,
56 })
57}
58
59// RollupBlock stores all the data related to the Rollup SC from an ethereum block
60type RollupBlock struct {
61 State eth.RollupState
62 Vars common.RollupVariables
63 Events eth.RollupEvents
64 Txs map[ethCommon.Hash]*types.Transaction
65 Constants *common.RollupConstants
66 Eth *EthereumBlock
67}
68
69func (r *RollupBlock) addTransaction(tx *types.Transaction) *types.Transaction {
70 txHash := tx.Hash()
71 r.Txs[txHash] = tx
72 return tx
73}
74
75var (
76 errBidClosed = fmt.Errorf("Bid has already been closed")
77 errBidNotOpen = fmt.Errorf("Bid has not been opened yet")
78 errBidBelowMin = fmt.Errorf("Bid below minimum")
79 errCoordNotReg = fmt.Errorf("Coordinator not registered")
80)
81
82// AuctionBlock stores all the data related to the Auction SC from an ethereum block
83type AuctionBlock struct {
84 State eth.AuctionState
85 Vars common.AuctionVariables
86 Events eth.AuctionEvents
87 Txs map[ethCommon.Hash]*types.Transaction
88 Constants *common.AuctionConstants
89 Eth *EthereumBlock
90}
91
92func (a *AuctionBlock) addTransaction(tx *types.Transaction) *types.Transaction {
93 txHash := tx.Hash()
94 a.Txs[txHash] = tx
95 return tx
96}
97
98func (a *AuctionBlock) getSlotNumber(blockNumber int64) int64 {
99 if a.Eth.BlockNum >= a.Constants.GenesisBlockNum {
100 return (blockNumber - a.Constants.GenesisBlockNum) / int64(a.Constants.BlocksPerSlot)
101 }
102 return 0
103}
104
105func (a *AuctionBlock) getCurrentSlotNumber() int64 {
106 return a.getSlotNumber(a.Eth.BlockNum)
107}
108
109func (a *AuctionBlock) getSlotSet(slot int64) int64 {
110 return slot % int64(len(a.Vars.DefaultSlotSetBid))
111}
112
113func (a *AuctionBlock) getMinBidBySlot(slot int64) (*big.Int, error) {
114 if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
115 return nil, tracerr.Wrap(errBidClosed)
116 }
117
118 slotSet := a.getSlotSet(slot)
119 // fmt.Println("slot:", slot, "slotSet:", slotSet)
120 var prevBid *big.Int
121 slotState, ok := a.State.Slots[slot]
122 if !ok {
123 slotState = eth.NewSlotState()
124 a.State.Slots[slot] = slotState
125 }
126 // If the bidAmount for a slot is 0 it means that it has not yet been
127 // bid, so the midBid will be the minimum bid for the slot time plus
128 // the outbidding set, otherwise it will be the bidAmount plus the
129 // outbidding
130 if slotState.BidAmount.Cmp(big.NewInt(0)) == 0 {
131 prevBid = a.Vars.DefaultSlotSetBid[slotSet]
132 } else {
133 prevBid = slotState.BidAmount
134 }
135 outBid := new(big.Int).Set(prevBid)
136 // fmt.Println("outBid:", outBid)
137 outBid.Mul(outBid, big.NewInt(int64(a.Vars.Outbidding)))
138 outBid.Div(outBid, big.NewInt(10000)) //nolint:gomnd
139 outBid.Add(prevBid, outBid)
140 // fmt.Println("minBid:", outBid)
141 return outBid, nil
142}
143
144func (a *AuctionBlock) forge(forger ethCommon.Address) error {
145 if ok, err := a.canForge(forger, a.Eth.BlockNum); err != nil {
146 return tracerr.Wrap(err)
147 } else if !ok {
148 return tracerr.Wrap(fmt.Errorf("Can't forge"))
149 }
150
151 slotToForge := a.getSlotNumber(a.Eth.BlockNum)
152 slotState, ok := a.State.Slots[slotToForge]
153 if !ok {
154 slotState = eth.NewSlotState()
155 a.State.Slots[slotToForge] = slotState
156 }
157
158 if !slotState.ForgerCommitment {
159 // Get the relativeBlock to check if the slotDeadline has been exceeded
160 relativeBlock := a.Eth.BlockNum - (a.Constants.GenesisBlockNum +
161 (slotToForge * int64(a.Constants.BlocksPerSlot)))
162 if relativeBlock < int64(a.Vars.SlotDeadline) {
163 slotState.ForgerCommitment = true
164 }
165 }
166
167 slotState.Fulfilled = true
168
169 a.Events.NewForge = append(a.Events.NewForge, eth.AuctionEventNewForge{
170 Forger: forger,
171 SlotToForge: slotToForge,
172 })
173 return nil
174}
175
176func (a *AuctionBlock) canForge(forger ethCommon.Address, blockNum int64) (bool, error) {
177 if blockNum < a.Constants.GenesisBlockNum {
178 return false, tracerr.Wrap(fmt.Errorf("Auction has not started yet"))
179 }
180
181 slotToForge := a.getSlotNumber(blockNum)
182 // fmt.Printf("DBG canForge slot: %v\n", slotToForge)
183 // Get the relativeBlock to check if the slotDeadline has been exceeded
184 relativeBlock := blockNum - (a.Constants.GenesisBlockNum + (slotToForge * int64(a.Constants.BlocksPerSlot)))
185
186 // If the closedMinBid is 0 it means that we have to take as minBid the
187 // one that is set for this slot set, otherwise the one that has been
188 // saved will be used
189 var minBid *big.Int
190 slotState, ok := a.State.Slots[slotToForge]
191 if !ok {
192 slotState = eth.NewSlotState()
193 a.State.Slots[slotToForge] = slotState
194 }
195 if slotState.ClosedMinBid.Cmp(big.NewInt(0)) == 0 {
196 minBid = a.Vars.DefaultSlotSetBid[a.getSlotSet(slotToForge)]
197 } else {
198 minBid = slotState.ClosedMinBid
199 }
200
201 if !slotState.ForgerCommitment && (relativeBlock >= int64(a.Vars.SlotDeadline)) {
202 // if the relative block has exceeded the slotDeadline and no
203 // batch has been forged, anyone can forge
204 return true, nil
205 } else if coord, ok := a.State.Coordinators[slotState.Bidder]; ok &&
206 coord.Forger == forger && slotState.BidAmount.Cmp(minBid) >= 0 {
207 // if forger bidAmount has exceeded the minBid it can forge
208 return true, nil
209 } else if a.Vars.BootCoordinator == forger && slotState.BidAmount.Cmp(minBid) == -1 {
210 // if it's the boot coordinator and it has not been bid or the
211 // bid is below the minimum it can forge
212 return true, nil
213 } else {
214 return false, nil
215 }
216}
217
218// EthereumBlock stores all the generic data related to the an ethereum block
219type EthereumBlock struct {
220 BlockNum int64
221 Time int64
222 Hash ethCommon.Hash
223 ParentHash ethCommon.Hash
224 Tokens map[ethCommon.Address]eth.ERC20Consts
225 Nonce uint64
226 // state ethState
227}
228
229// Block represents a ethereum block
230type Block struct {
231 Rollup *RollupBlock
232 Auction *AuctionBlock
233 WDelayer *WDelayerBlock
234 Eth *EthereumBlock
235}
236
237func (b *Block) copy() *Block {
238 bCopyRaw, err := copystructure.Copy(b)
239 if err != nil {
240 panic(err)
241 }
242 bCopy := bCopyRaw.(*Block)
243 return bCopy
244}
245
246// Next prepares the successive block.
247func (b *Block) Next() *Block {
248 blockNext := b.copy()
249 blockNext.Rollup.Events = eth.NewRollupEvents()
250 blockNext.Auction.Events = eth.NewAuctionEvents()
251
252 blockNext.Eth.BlockNum = b.Eth.BlockNum + 1
253 blockNext.Eth.ParentHash = b.Eth.Hash
254
255 blockNext.Rollup.Constants = b.Rollup.Constants
256 blockNext.Auction.Constants = b.Auction.Constants
257 blockNext.WDelayer.Constants = b.WDelayer.Constants
258 blockNext.Rollup.Eth = blockNext.Eth
259 blockNext.Auction.Eth = blockNext.Eth
260 blockNext.WDelayer.Eth = blockNext.Eth
261
262 return blockNext
263}
264
265// ClientSetup is used to initialize the constants of the Smart Contracts and
266// other details of the test Client
267type ClientSetup struct {
268 RollupConstants *common.RollupConstants
269 RollupVariables *common.RollupVariables
270 AuctionConstants *common.AuctionConstants
271 AuctionVariables *common.AuctionVariables
272 WDelayerConstants *common.WDelayerConstants
273 WDelayerVariables *common.WDelayerVariables
274 VerifyProof bool
275}
276
277// NewClientSetupExample returns a ClientSetup example with hardcoded realistic
278// values. With this setup, the rollup genesis will be block 1, and block 0
279// and 1 will be premined.
280//nolint:gomnd
281func NewClientSetupExample() *ClientSetup {
282 // rfield, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
283 // if !ok {
284 // panic("bad rfield")
285 // }
286 initialMinimalBidding, ok := new(big.Int).SetString("10000000000000000000", 10) // 10 * (1e18)
287 if !ok {
288 panic("bad initialMinimalBidding")
289 }
290 tokenHEZ := ethCommon.HexToAddress("0x51D243D62852Bba334DD5cc33f242BAc8c698074")
291 governanceAddress := ethCommon.HexToAddress("0x688EfD95BA4391f93717CF02A9aED9DBD2855cDd")
292 rollupConstants := &common.RollupConstants{
293 Verifiers: []common.RollupVerifierStruct{
294 {
295 MaxTx: 2048,
296 NLevels: 32,
297 },
298 },
299 TokenHEZ: tokenHEZ,
300 HermezGovernanceAddress: governanceAddress,
301 HermezAuctionContract: ethCommon.HexToAddress("0x8E442975805fb1908f43050c9C1A522cB0e28D7b"),
302 WithdrawDelayerContract: ethCommon.HexToAddress("0x5CB7979cBdbf65719BEE92e4D15b7b7Ed3D79114"),
303 }
304 var buckets [common.RollupConstNumBuckets]common.BucketParams
305 for i := range buckets {
306 buckets[i] = common.BucketParams{
307 CeilUSD: big.NewInt(0),
308 Withdrawals: big.NewInt(0),
309 BlockWithdrawalRate: big.NewInt(0),
310 MaxWithdrawals: big.NewInt(0),
311 }
312 }
313 rollupVariables := &common.RollupVariables{
314 FeeAddToken: big.NewInt(11),
315 ForgeL1L2BatchTimeout: 9,
316 WithdrawalDelay: 80,
317 Buckets: buckets,
318 }
319 auctionConstants := &common.AuctionConstants{
320 BlocksPerSlot: 40,
321 InitialMinimalBidding: initialMinimalBidding,
322 GenesisBlockNum: 1,
323 GovernanceAddress: governanceAddress,
324 TokenHEZ: tokenHEZ,
325 HermezRollup: ethCommon.HexToAddress("0x474B6e29852257491cf283EfB1A9C61eBFe48369"),
326 }
327 auctionVariables := &common.AuctionVariables{
328 DonationAddress: ethCommon.HexToAddress("0x61Ed87CF0A1496b49A420DA6D84B58196b98f2e7"),
329 BootCoordinator: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
330 BootCoordinatorURL: "https://boot.coordinator.com",
331 DefaultSlotSetBid: [6]*big.Int{
332 initialMinimalBidding, initialMinimalBidding, initialMinimalBidding,
333 initialMinimalBidding, initialMinimalBidding, initialMinimalBidding,
334 },
335 ClosedAuctionSlots: 2,
336 OpenAuctionSlots: 4320,
337 AllocationRatio: [3]uint16{4000, 4000, 2000},
338 Outbidding: 1000,
339 SlotDeadline: 20,
340 }
341 wDelayerConstants := &common.WDelayerConstants{
342 MaxWithdrawalDelay: 60 * 60 * 24 * 7 * 2, // 2 weeks
343 MaxEmergencyModeTime: 60 * 60 * 24 * 7 * 26, // 26 weeks
344 HermezRollup: auctionConstants.HermezRollup,
345 }
346 wDelayerVariables := &common.WDelayerVariables{
347 HermezGovernanceAddress: ethCommon.HexToAddress("0xcfD0d163AE6432a72682323E2C3A5a69e6B37D12"),
348 EmergencyCouncilAddress: ethCommon.HexToAddress("0x2730700932a4FDB97B9268A3Ca29f97Ea5fd7EA0"),
349 WithdrawalDelay: 60,
350 EmergencyModeStartingBlock: 0,
351 EmergencyMode: false,
352 }
353 return &ClientSetup{
354 RollupConstants: rollupConstants,
355 RollupVariables: rollupVariables,
356 AuctionConstants: auctionConstants,
357 AuctionVariables: auctionVariables,
358 WDelayerConstants: wDelayerConstants,
359 WDelayerVariables: wDelayerVariables,
360 }
361}
362
363// Timer is an interface to simulate a source of time, useful to advance time
364// virtually.
365type Timer interface {
366 Time() int64
367}
368
369// type forgeBatchArgs struct {
370// ethTx *types.Transaction
371// blockNum int64
372// blockHash ethCommon.Hash
373// }
374
375type batch struct {
376 ForgeBatchArgs eth.RollupForgeBatchArgs
377 Sender ethCommon.Address
378}
379
380// Client implements the eth.ClientInterface interface, allowing to manipulate the
381// values for testing, working with deterministic results.
382type Client struct {
383 rw *sync.RWMutex
384 log bool
385 addr *ethCommon.Address
386 rollupConstants *common.RollupConstants
387 auctionConstants *common.AuctionConstants
388 wDelayerConstants *common.WDelayerConstants
389 blocks map[int64]*Block
390 // state state
391 blockNum int64 // last mined block num
392 maxBlockNum int64 // highest block num calculated
393 timer Timer
394 hasher hasher
395
396 forgeBatchArgsPending map[ethCommon.Hash]*batch
397 forgeBatchArgs map[ethCommon.Hash]*batch
398}
399
400// NewClient returns a new test Client that implements the eth.IClient
401// interface, at the given initialBlockNumber.
402func NewClient(l bool, timer Timer, addr *ethCommon.Address, setup *ClientSetup) *Client {
403 blocks := make(map[int64]*Block)
404 blockNum := int64(0)
405
406 hasher := hasher{}
407 // Add ethereum genesis block
408 mapL1TxQueue := make(map[int64]*eth.QueueStruct)
409 mapL1TxQueue[0] = eth.NewQueueStruct()
410 mapL1TxQueue[1] = eth.NewQueueStruct()
411 blockCurrent := &Block{
412 Rollup: &RollupBlock{
413 State: eth.RollupState{
414 StateRoot: big.NewInt(0),
415 ExitRoots: make([]*big.Int, 1),
416 ExitNullifierMap: make(map[int64]map[int64]bool),
417 // TokenID = 0 is ETH. Set first entry in TokenList with 0x0 address for ETH.
418 TokenList: []ethCommon.Address{{}},
419 TokenMap: make(map[ethCommon.Address]bool),
420 MapL1TxQueue: mapL1TxQueue,
421 LastL1L2Batch: 0,
422 CurrentToForgeL1TxsNum: 0,
423 LastToForgeL1TxsNum: 1,
424 CurrentIdx: 0,
425 },
426 Vars: *setup.RollupVariables,
427 Txs: make(map[ethCommon.Hash]*types.Transaction),
428 Events: eth.NewRollupEvents(),
429 Constants: setup.RollupConstants,
430 },
431 Auction: &AuctionBlock{
432 State: eth.AuctionState{
433 Slots: make(map[int64]*eth.SlotState),
434 PendingBalances: make(map[ethCommon.Address]*big.Int),
435 Coordinators: make(map[ethCommon.Address]*eth.Coordinator),
436 },
437 Vars: *setup.AuctionVariables,
438 Txs: make(map[ethCommon.Hash]*types.Transaction),
439 Events: eth.NewAuctionEvents(),
440 Constants: setup.AuctionConstants,
441 },
442 WDelayer: &WDelayerBlock{
443 // State: TODO
444 Vars: *setup.WDelayerVariables,
445 Txs: make(map[ethCommon.Hash]*types.Transaction),
446 Events: eth.NewWDelayerEvents(),
447 Constants: setup.WDelayerConstants,
448 },
449 Eth: &EthereumBlock{
450 BlockNum: blockNum,
451 Time: timer.Time(),
452 Hash: hasher.Next(),
453 ParentHash: ethCommon.Hash{},
454 Tokens: make(map[ethCommon.Address]eth.ERC20Consts),
455 },
456 }
457 blockCurrent.Rollup.Eth = blockCurrent.Eth
458 blockCurrent.Auction.Eth = blockCurrent.Eth
459 blocks[blockNum] = blockCurrent
460 blockNext := blockCurrent.Next()
461 blocks[blockNum+1] = blockNext
462
463 c := Client{
464 rw: &sync.RWMutex{},
465 log: l,
466 addr: addr,
467 rollupConstants: setup.RollupConstants,
468 auctionConstants: setup.AuctionConstants,
469 wDelayerConstants: setup.WDelayerConstants,
470 blocks: blocks,
471 timer: timer,
472 hasher: hasher,
473 forgeBatchArgsPending: make(map[ethCommon.Hash]*batch),
474 forgeBatchArgs: make(map[ethCommon.Hash]*batch),
475 blockNum: blockNum,
476 maxBlockNum: blockNum,
477 }
478
479 for i := int64(1); i < setup.AuctionConstants.GenesisBlockNum+1; i++ {
480 c.CtlMineBlock()
481 }
482
483 return &c
484}
485
486//
487// Mock Control
488//
489
490func (c *Client) setNextBlock(block *Block) {
491 c.blocks[c.blockNum+1] = block
492}
493
494func (c *Client) revertIfErr(err error, block *Block) {
495 if err != nil {
496 log.Infow("TestClient revert", "block", block.Eth.BlockNum, "err", err)
497 c.setNextBlock(block)
498 }
499}
500
501// Debugf calls log.Debugf if c.log is true
502func (c *Client) Debugf(template string, args ...interface{}) {
503 if c.log {
504 log.Debugf(template, args...)
505 }
506}
507
508// Debugw calls log.Debugw if c.log is true
509func (c *Client) Debugw(template string, kv ...interface{}) {
510 if c.log {
511 log.Debugw(template, kv...)
512 }
513}
514
515type hasher struct {
516 counter uint64
517}
518
519// Next returns the next hash
520func (h *hasher) Next() ethCommon.Hash {
521 var hash ethCommon.Hash
522 binary.LittleEndian.PutUint64(hash[:], h.counter)
523 h.counter++
524 return hash
525}
526
527func (c *Client) nextBlock() *Block {
528 return c.blocks[c.blockNum+1]
529}
530
531func (c *Client) currentBlock() *Block {
532 return c.blocks[c.blockNum]
533}
534
535// CtlSetAddr sets the address of the client
536func (c *Client) CtlSetAddr(addr ethCommon.Address) {
537 c.addr = &addr
538}
539
540// CtlMineBlock moves one block forward
541func (c *Client) CtlMineBlock() {
542 c.rw.Lock()
543 defer c.rw.Unlock()
544
545 blockCurrent := c.nextBlock()
546 c.blockNum++
547 c.maxBlockNum = c.blockNum
548 blockCurrent.Eth.Time = c.timer.Time()
549 blockCurrent.Eth.Hash = c.hasher.Next()
550 for ethTxHash, forgeBatchArgs := range c.forgeBatchArgsPending {
551 c.forgeBatchArgs[ethTxHash] = forgeBatchArgs
552 }
553 c.forgeBatchArgsPending = make(map[ethCommon.Hash]*batch)
554
555 blockNext := blockCurrent.Next()
556 c.blocks[c.blockNum+1] = blockNext
557 c.Debugw("TestClient mined block", "blockNum", c.blockNum)
558}
559
560// CtlRollback discards the last mined block. Use this to replace a mined
561// block to simulate reorgs.
562func (c *Client) CtlRollback() {
563 c.rw.Lock()
564 defer c.rw.Unlock()
565
566 if c.blockNum == 0 {
567 panic("Can't rollback at blockNum = 0")
568 }
569 delete(c.blocks, c.blockNum+1) // delete next block
570 delete(c.blocks, c.blockNum) // delete current block
571 c.blockNum--
572 blockCurrent := c.blocks[c.blockNum]
573 blockNext := blockCurrent.Next()
574 c.blocks[c.blockNum+1] = blockNext
575}
576
577//
578// Ethereum
579//
580
581// CtlLastBlock returns the last blockNum without checks
582func (c *Client) CtlLastBlock() *common.Block {
583 c.rw.RLock()
584 defer c.rw.RUnlock()
585
586 block := c.blocks[c.blockNum]
587 return &common.Block{
588 Num: c.blockNum,
589 Timestamp: time.Unix(block.Eth.Time, 0),
590 Hash: block.Eth.Hash,
591 ParentHash: block.Eth.ParentHash,
592 }
593}
594
595// CtlLastForgedBatch returns the last batchNum without checks
596func (c *Client) CtlLastForgedBatch() int64 {
597 c.rw.RLock()
598 defer c.rw.RUnlock()
599
600 currentBlock := c.currentBlock()
601 e := currentBlock.Rollup
602 return int64(len(e.State.ExitRoots)) - 1
603}
604
605// EthLastBlock returns the last blockNum
606func (c *Client) EthLastBlock() (int64, error) {
607 c.rw.RLock()
608 defer c.rw.RUnlock()
609
610 if c.blockNum < c.maxBlockNum {
611 panic("blockNum has decreased. " +
612 "After a rollback you must mine to reach the same or higher blockNum")
613 }
614 return c.blockNum, nil
615}
616
617// EthTransactionReceipt returns the transaction receipt of the given txHash
618func (c *Client) EthTransactionReceipt(ctx context.Context, txHash ethCommon.Hash) (*types.Receipt, error) {
619 c.rw.RLock()
620 defer c.rw.RUnlock()
621
622 for i := int64(0); i < c.blockNum; i++ {
623 b := c.blocks[i]
624 _, ok := b.Rollup.Txs[txHash]
625 if !ok {
626 _, ok = b.Auction.Txs[txHash]
627 }
628 if ok {
629 return &types.Receipt{
630 TxHash: txHash,
631 Status: types.ReceiptStatusSuccessful,
632 BlockHash: b.Eth.Hash,
633 BlockNumber: big.NewInt(b.Eth.BlockNum),
634 }, nil
635 }
636 }
637
638 return nil, nil
639}
640
641// CtlAddERC20 adds an ERC20 token to the blockchain.
642func (c *Client) CtlAddERC20(tokenAddr ethCommon.Address, constants eth.ERC20Consts) {
643 nextBlock := c.nextBlock()
644 e := nextBlock.Eth
645 e.Tokens[tokenAddr] = constants
646}
647
648// EthERC20Consts returns the constants defined for a particular ERC20 Token instance.
649func (c *Client) EthERC20Consts(tokenAddr ethCommon.Address) (*eth.ERC20Consts, error) {
650 currentBlock := c.currentBlock()
651 e := currentBlock.Eth
652 if constants, ok := e.Tokens[tokenAddr]; ok {
653 return &constants, nil
654 }
655 return nil, tracerr.Wrap(fmt.Errorf("tokenAddr not found"))
656}
657
658// func newHeader(number *big.Int) *types.Header {
659// return &types.Header{
660// Number: number,
661// Time: uint64(number.Int64()),
662// }
663// }
664
665// EthHeaderByNumber returns the *types.Header for the given block number in a
666// deterministic way.
667// func (c *Client) EthHeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
668// return newHeader(number), nil
669// }
670
671// EthBlockByNumber returns the *common.Block for the given block number in a
672// deterministic way. If number == -1, the latests known block is returned.
673func (c *Client) EthBlockByNumber(ctx context.Context, blockNum int64) (*common.Block, error) {
674 c.rw.RLock()
675 defer c.rw.RUnlock()
676
677 if blockNum > c.blockNum {
678 return nil, ethereum.NotFound
679 }
680 if blockNum == -1 {
681 blockNum = c.blockNum
682 }
683 block := c.blocks[blockNum]
684 return &common.Block{
685 Num: blockNum,
686 Timestamp: time.Unix(block.Eth.Time, 0),
687 Hash: block.Eth.Hash,
688 ParentHash: block.Eth.ParentHash,
689 }, nil
690}
691
692// EthAddress returns the ethereum address of the account loaded into the Client
693func (c *Client) EthAddress() (*ethCommon.Address, error) {
694 if c.addr == nil {
695 return nil, tracerr.Wrap(eth.ErrAccountNil)
696 }
697 return c.addr, nil
698}
699
700var errTODO = fmt.Errorf("TODO: Not implemented yet")
701
702//
703// Rollup
704//
705
706// CtlAddL1TxUser adds an L1TxUser to the L1UserTxs queue of the Rollup
707// func (c *Client) CtlAddL1TxUser(l1Tx *common.L1Tx) {
708// c.rw.Lock()
709// defer c.rw.Unlock()
710//
711// nextBlock := c.nextBlock()
712// r := nextBlock.Rollup
713// queue := r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
714// if len(queue.L1TxQueue) >= eth.RollupConstMaxL1UserTx {
715// r.State.LastToForgeL1TxsNum++
716// r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
717// queue = r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
718// }
719// if int64(l1Tx.FromIdx) > r.State.CurrentIdx {
720// panic("l1Tx.FromIdx > r.State.CurrentIdx")
721// }
722// if int(l1Tx.TokenID)+1 > len(r.State.TokenList) {
723// panic("l1Tx.TokenID + 1 > len(r.State.TokenList)")
724// }
725// queue.L1TxQueue = append(queue.L1TxQueue, *l1Tx)
726// r.Events.L1UserTx = append(r.Events.L1UserTx, eth.RollupEventL1UserTx{
727// L1Tx: *l1Tx,
728// ToForgeL1TxsNum: r.State.LastToForgeL1TxsNum,
729// Position: len(queue.L1TxQueue) - 1,
730// })
731// }
732
733// RollupL1UserTxERC20Permit is the interface to call the smart contract function
734func (c *Client) RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error) {
735 log.Error("TODO")
736 return nil, tracerr.Wrap(errTODO)
737}
738
739// RollupL1UserTxERC20ETH sends an L1UserTx to the Rollup.
740func (c *Client) RollupL1UserTxERC20ETH(
741 fromBJJ *babyjub.PublicKey,
742 fromIdx int64,
743 depositAmount *big.Int,
744 amount *big.Int,
745 tokenID uint32,
746 toIdx int64,
747) (tx *types.Transaction, err error) {
748 c.rw.Lock()
749 defer c.rw.Unlock()
750 cpy := c.nextBlock().copy()
751 defer func() { c.revertIfErr(err, cpy) }()
752
753 _, err = common.NewFloat16(amount)
754 if err != nil {
755 return nil, tracerr.Wrap(err)
756 }
757 _, err = common.NewFloat16(depositAmount)
758 if err != nil {
759 return nil, tracerr.Wrap(err)
760 }
761
762 nextBlock := c.nextBlock()
763 r := nextBlock.Rollup
764 queue := r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
765 if len(queue.L1TxQueue) >= common.RollupConstMaxL1UserTx {
766 r.State.LastToForgeL1TxsNum++
767 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
768 queue = r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
769 }
770 if fromIdx > r.State.CurrentIdx {
771 panic("l1Tx.FromIdx > r.State.CurrentIdx")
772 }
773 if int(tokenID)+1 > len(r.State.TokenList) {
774 panic("l1Tx.TokenID + 1 > len(r.State.TokenList)")
775 }
776 toForgeL1TxsNum := r.State.LastToForgeL1TxsNum
777 l1Tx, err := common.NewL1Tx(&common.L1Tx{
778 FromIdx: common.Idx(fromIdx),
779 FromEthAddr: *c.addr,
780 FromBJJ: fromBJJ,
781 Amount: amount,
782 DepositAmount: depositAmount,
783 TokenID: common.TokenID(tokenID),
784 ToIdx: common.Idx(toIdx),
785 ToForgeL1TxsNum: &toForgeL1TxsNum,
786 Position: len(queue.L1TxQueue),
787 UserOrigin: true,
788 })
789 if err != nil {
790 return nil, tracerr.Wrap(err)
791 }
792
793 queue.L1TxQueue = append(queue.L1TxQueue, *l1Tx)
794 r.Events.L1UserTx = append(r.Events.L1UserTx, eth.RollupEventL1UserTx{
795 L1UserTx: *l1Tx,
796 })
797 return r.addTransaction(c.newTransaction("l1UserTxERC20ETH", l1Tx)), nil
798}
799
800// RollupL1UserTxERC777 is the interface to call the smart contract function
801// func (c *Client) RollupL1UserTxERC777(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error) {
802// log.Error("TODO")
803// return nil, errTODO
804// }
805
806// RollupRegisterTokensCount is the interface to call the smart contract function
807func (c *Client) RollupRegisterTokensCount() (*big.Int, error) {
808 log.Error("TODO")
809 return nil, tracerr.Wrap(errTODO)
810}
811
812// RollupLastForgedBatch is the interface to call the smart contract function
813func (c *Client) RollupLastForgedBatch() (int64, error) {
814 c.rw.RLock()
815 defer c.rw.RUnlock()
816
817 currentBlock := c.currentBlock()
818 e := currentBlock.Rollup
819 return int64(len(e.State.ExitRoots)) - 1, nil
820}
821
822// RollupWithdrawCircuit is the interface to call the smart contract function
823func (c *Client) RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error) {
824 log.Error("TODO")
825 return nil, tracerr.Wrap(errTODO)
826}
827
828// RollupWithdrawMerkleProof is the interface to call the smart contract function
829func (c *Client) RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) {
830 c.rw.Lock()
831 defer c.rw.Unlock()
832 cpy := c.nextBlock().copy()
833 defer func() { c.revertIfErr(err, cpy) }()
834
835 nextBlock := c.nextBlock()
836 r := nextBlock.Rollup
837
838 if int(numExitRoot) >= len(r.State.ExitRoots) {
839 return nil, tracerr.Wrap(fmt.Errorf("numExitRoot >= len(r.State.ExitRoots)"))
840 }
841 if _, ok := r.State.ExitNullifierMap[numExitRoot][idx]; ok {
842 return nil, tracerr.Wrap(fmt.Errorf("exit already withdrawn"))
843 }
844 r.State.ExitNullifierMap[numExitRoot][idx] = true
845
846 type data struct {
847 BabyPubKey *babyjub.PublicKey
848 TokenID uint32
849 NumExitRoot int64
850 Idx int64
851 Amount *big.Int
852 Siblings []*big.Int
853 InstantWithdraw bool
854 }
855 tx = r.addTransaction(c.newTransaction("withdrawMerkleProof", data{
856 BabyPubKey: babyPubKey,
857 TokenID: tokenID,
858 NumExitRoot: numExitRoot,
859 Idx: idx,
860 Amount: amount,
861 Siblings: siblings,
862 InstantWithdraw: instantWithdraw,
863 }))
864 r.Events.Withdraw = append(r.Events.Withdraw, eth.RollupEventWithdraw{
865 Idx: uint64(idx),
866 NumExitRoot: uint64(numExitRoot),
867 InstantWithdraw: instantWithdraw,
868 TxHash: tx.Hash(),
869 })
870
871 if !instantWithdraw {
872 w := nextBlock.WDelayer
873 w.deposit(tx.Hash(), *c.addr, r.State.TokenList[int(tokenID)], amount)
874 }
875 return tx, nil
876}
877
878type transactionData struct {
879 Name string
880 Value interface{}
881}
882
883func (c *Client) newTransaction(name string, value interface{}) *types.Transaction {
884 eth := c.nextBlock().Eth
885 nonce := eth.Nonce
886 eth.Nonce++
887 data, err := json.Marshal(transactionData{name, value})
888 if err != nil {
889 panic(err)
890 }
891 return types.NewTransaction(nonce, ethCommon.Address{}, nil, 0, nil,
892 data)
893}
894
895// RollupForgeBatch is the interface to call the smart contract function
896func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs) (tx *types.Transaction, err error) {
897 c.rw.Lock()
898 defer c.rw.Unlock()
899 cpy := c.nextBlock().copy()
900 defer func() { c.revertIfErr(err, cpy) }()
901 if c.addr == nil {
902 return nil, tracerr.Wrap(eth.ErrAccountNil)
903 }
904
905 a := c.nextBlock().Auction
906 ok, err := a.canForge(*c.addr, a.Eth.BlockNum)
907 if err != nil {
908 return nil, tracerr.Wrap(err)
909 }
910 if !ok {
911 return nil, tracerr.Wrap(fmt.Errorf(common.AuctionErrMsgCannotForge))
912 }
913
914 // TODO: Verify proof
915
916 // Auction
917 err = a.forge(*c.addr)
918 if err != nil {
919 return nil, tracerr.Wrap(err)
920 }
921
922 // TODO: If successful, store the tx in a successful array.
923 // TODO: If failed, store the tx in a failed array.
924 // TODO: Add method to move the tx to another block, reapply it there, and possibly go from successful to failed.
925
926 return c.addBatch(args)
927}
928
929// CtlAddBatch adds forged batch to the Rollup, without checking any ZKProof
930func (c *Client) CtlAddBatch(args *eth.RollupForgeBatchArgs) {
931 c.rw.Lock()
932 defer c.rw.Unlock()
933
934 if _, err := c.addBatch(args); err != nil {
935 panic(err)
936 }
937}
938
939func (c *Client) addBatch(args *eth.RollupForgeBatchArgs) (*types.Transaction, error) {
940 nextBlock := c.nextBlock()
941 r := nextBlock.Rollup
942 r.State.StateRoot = args.NewStRoot
943 if args.NewLastIdx < r.State.CurrentIdx {
944 return nil, tracerr.Wrap(fmt.Errorf("args.NewLastIdx < r.State.CurrentIdx"))
945 }
946 r.State.CurrentIdx = args.NewLastIdx
947 r.State.ExitNullifierMap[int64(len(r.State.ExitRoots))] = make(map[int64]bool)
948 r.State.ExitRoots = append(r.State.ExitRoots, args.NewExitRoot)
949 if args.L1Batch {
950 r.State.CurrentToForgeL1TxsNum++
951 if r.State.CurrentToForgeL1TxsNum == r.State.LastToForgeL1TxsNum {
952 r.State.LastToForgeL1TxsNum++
953 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
954 }
955 }
956 ethTx := r.addTransaction(c.newTransaction("forgebatch", args))
957 c.forgeBatchArgsPending[ethTx.Hash()] = &batch{*args, *c.addr}
958 r.Events.ForgeBatch = append(r.Events.ForgeBatch, eth.RollupEventForgeBatch{
959 BatchNum: int64(len(r.State.ExitRoots)) - 1,
960 EthTxHash: ethTx.Hash(),
961 L1UserTxsLen: uint16(len(args.L1UserTxs)),
962 })
963
964 return ethTx, nil
965}
966
967// RollupAddTokenSimple is a wrapper around RollupAddToken that automatically
968// sets `deadlie`.
969func (c *Client) RollupAddTokenSimple(tokenAddress ethCommon.Address, feeAddToken *big.Int) (tx *types.Transaction, err error) {
970 return c.RollupAddToken(tokenAddress, feeAddToken, big.NewInt(9999)) //nolint:gomnd
971}
972
973// RollupAddToken is the interface to call the smart contract function
974func (c *Client) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken *big.Int,
975 deadline *big.Int) (tx *types.Transaction, err error) {
976 c.rw.Lock()
977 defer c.rw.Unlock()
978 cpy := c.nextBlock().copy()
979 defer func() { c.revertIfErr(err, cpy) }()
980 if c.addr == nil {
981 return nil, tracerr.Wrap(eth.ErrAccountNil)
982 }
983
984 nextBlock := c.nextBlock()
985 r := nextBlock.Rollup
986 if _, ok := r.State.TokenMap[tokenAddress]; ok {
987 return nil, tracerr.Wrap(fmt.Errorf("Token %v already registered", tokenAddress))
988 }
989 if feeAddToken.Cmp(r.Vars.FeeAddToken) != 0 {
990 return nil, tracerr.Wrap(fmt.Errorf("Expected fee: %v but got: %v", r.Vars.FeeAddToken, feeAddToken))
991 }
992
993 r.State.TokenMap[tokenAddress] = true
994 r.State.TokenList = append(r.State.TokenList, tokenAddress)
995 r.Events.AddToken = append(r.Events.AddToken, eth.RollupEventAddToken{TokenAddress: tokenAddress,
996 TokenID: uint32(len(r.State.TokenList) - 1)})
997 return r.addTransaction(c.newTransaction("addtoken", tokenAddress)), nil
998}
999
1000// RollupGetCurrentTokens is the interface to call the smart contract function
1001func (c *Client) RollupGetCurrentTokens() (*big.Int, error) {
1002 c.rw.RLock()
1003 defer c.rw.RUnlock()
1004
1005 log.Error("TODO")
1006 return nil, tracerr.Wrap(errTODO)
1007}
1008
1009// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
1010func (c *Client) RollupUpdateForgeL1L2BatchTimeout(newForgeL1Timeout int64) (tx *types.Transaction, err error) {
1011 c.rw.Lock()
1012 defer c.rw.Unlock()
1013 cpy := c.nextBlock().copy()
1014 defer func() { c.revertIfErr(err, cpy) }()
1015 if c.addr == nil {
1016 return nil, tracerr.Wrap(eth.ErrAccountNil)
1017 }
1018
1019 nextBlock := c.nextBlock()
1020 r := nextBlock.Rollup
1021 r.Vars.ForgeL1L2BatchTimeout = newForgeL1Timeout
1022 r.Events.UpdateForgeL1L2BatchTimeout = append(r.Events.UpdateForgeL1L2BatchTimeout,
1023 eth.RollupEventUpdateForgeL1L2BatchTimeout{NewForgeL1L2BatchTimeout: newForgeL1Timeout})
1024
1025 return r.addTransaction(c.newTransaction("updateForgeL1L2BatchTimeout", newForgeL1Timeout)), nil
1026}
1027
1028// RollupUpdateFeeAddToken is the interface to call the smart contract function
1029func (c *Client) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
1030 c.rw.Lock()
1031 defer c.rw.Unlock()
1032 cpy := c.nextBlock().copy()
1033 defer func() { c.revertIfErr(err, cpy) }()
1034 if c.addr == nil {
1035 return nil, tracerr.Wrap(eth.ErrAccountNil)
1036 }
1037
1038 log.Error("TODO")
1039 return nil, tracerr.Wrap(errTODO)
1040}
1041
1042// RollupUpdateTokensHEZ is the interface to call the smart contract function
1043// func (c *Client) RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (tx *types.Transaction, err error) {
1044// c.rw.Lock()
1045// defer c.rw.Unlock()
1046// cpy := c.nextBlock().copy()
1047// defer func() { c.revertIfErr(err, cpy) }()
1048//
1049// log.Error("TODO")
1050// return nil, errTODO
1051// }
1052
1053// RollupUpdateGovernance is the interface to call the smart contract function
1054// func (c *Client) RollupUpdateGovernance() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol)
1055// return nil, errTODO
1056// }
1057
1058// RollupConstants returns the Constants of the Rollup Smart Contract
1059func (c *Client) RollupConstants() (*common.RollupConstants, error) {
1060 c.rw.RLock()
1061 defer c.rw.RUnlock()
1062
1063 return c.rollupConstants, nil
1064}
1065
1066// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
1067func (c *Client) RollupEventsByBlock(blockNum int64) (*eth.RollupEvents, *ethCommon.Hash, error) {
1068 c.rw.RLock()
1069 defer c.rw.RUnlock()
1070
1071 block, ok := c.blocks[blockNum]
1072 if !ok {
1073 return nil, nil, tracerr.Wrap(fmt.Errorf("Block %v doesn't exist", blockNum))
1074 }
1075 return &block.Rollup.Events, &block.Eth.Hash, nil
1076}
1077
1078// RollupEventInit returns the initialize event with its corresponding block number
1079func (c *Client) RollupEventInit() (*eth.RollupEventInitialize, int64, error) {
1080 vars := c.blocks[0].Rollup.Vars
1081 return ð.RollupEventInitialize{
1082 ForgeL1L2BatchTimeout: uint8(vars.ForgeL1L2BatchTimeout),
1083 FeeAddToken: vars.FeeAddToken,
1084 WithdrawalDelay: vars.WithdrawalDelay,
1085 }, 1, nil
1086}
1087
1088// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the Rollup Smart Contract in the given transaction
1089func (c *Client) RollupForgeBatchArgs(ethTxHash ethCommon.Hash, l1UserTxsLen uint16) (*eth.RollupForgeBatchArgs, *ethCommon.Address, error) {
1090 c.rw.RLock()
1091 defer c.rw.RUnlock()
1092
1093 batch, ok := c.forgeBatchArgs[ethTxHash]
1094 if !ok {
1095 return nil, nil, tracerr.Wrap(fmt.Errorf("transaction not found"))
1096 }
1097 return &batch.ForgeBatchArgs, &batch.Sender, nil
1098}
1099
1100//
1101// Auction
1102//
1103
1104// AuctionSetSlotDeadline is the interface to call the smart contract function
1105func (c *Client) AuctionSetSlotDeadline(newDeadline uint8) (tx *types.Transaction, err error) {
1106 c.rw.Lock()
1107 defer c.rw.Unlock()
1108 cpy := c.nextBlock().copy()
1109 defer func() { c.revertIfErr(err, cpy) }()
1110 if c.addr == nil {
1111 return nil, tracerr.Wrap(eth.ErrAccountNil)
1112 }
1113
1114 log.Error("TODO")
1115 return nil, tracerr.Wrap(errTODO)
1116}
1117
1118// AuctionGetSlotDeadline is the interface to call the smart contract function
1119func (c *Client) AuctionGetSlotDeadline() (uint8, error) {
1120 c.rw.RLock()
1121 defer c.rw.RUnlock()
1122
1123 log.Error("TODO")
1124 return 0, tracerr.Wrap(errTODO)
1125}
1126
1127// AuctionSetOpenAuctionSlots is the interface to call the smart contract function
1128func (c *Client) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (tx *types.Transaction, err error) {
1129 c.rw.Lock()
1130 defer c.rw.Unlock()
1131 cpy := c.nextBlock().copy()
1132 defer func() { c.revertIfErr(err, cpy) }()
1133 if c.addr == nil {
1134 return nil, tracerr.Wrap(eth.ErrAccountNil)
1135 }
1136
1137 nextBlock := c.nextBlock()
1138 a := nextBlock.Auction
1139 a.Vars.OpenAuctionSlots = newOpenAuctionSlots
1140 a.Events.NewOpenAuctionSlots = append(a.Events.NewOpenAuctionSlots,
1141 eth.AuctionEventNewOpenAuctionSlots{NewOpenAuctionSlots: newOpenAuctionSlots})
1142
1143 return a.addTransaction(c.newTransaction("setOpenAuctionSlots", newOpenAuctionSlots)), nil
1144}
1145
1146// AuctionGetOpenAuctionSlots is the interface to call the smart contract function
1147func (c *Client) AuctionGetOpenAuctionSlots() (uint16, error) {
1148 c.rw.RLock()
1149 defer c.rw.RUnlock()
1150
1151 log.Error("TODO")
1152 return 0, tracerr.Wrap(errTODO)
1153}
1154
1155// AuctionSetClosedAuctionSlots is the interface to call the smart contract function
1156func (c *Client) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (tx *types.Transaction, err error) {
1157 c.rw.Lock()
1158 defer c.rw.Unlock()
1159 cpy := c.nextBlock().copy()
1160 defer func() { c.revertIfErr(err, cpy) }()
1161 if c.addr == nil {
1162 return nil, tracerr.Wrap(eth.ErrAccountNil)
1163 }
1164
1165 log.Error("TODO")
1166 return nil, tracerr.Wrap(errTODO)
1167}
1168
1169// AuctionGetClosedAuctionSlots is the interface to call the smart contract function
1170func (c *Client) AuctionGetClosedAuctionSlots() (uint16, error) {
1171 c.rw.RLock()
1172 defer c.rw.RUnlock()
1173
1174 log.Error("TODO")
1175 return 0, tracerr.Wrap(errTODO)
1176}
1177
1178// AuctionSetOutbidding is the interface to call the smart contract function
1179func (c *Client) AuctionSetOutbidding(newOutbidding uint16) (tx *types.Transaction, err error) {
1180 c.rw.Lock()
1181 defer c.rw.Unlock()
1182 cpy := c.nextBlock().copy()
1183 defer func() { c.revertIfErr(err, cpy) }()
1184 if c.addr == nil {
1185 return nil, tracerr.Wrap(eth.ErrAccountNil)
1186 }
1187
1188 log.Error("TODO")
1189 return nil, tracerr.Wrap(errTODO)
1190}
1191
1192// AuctionGetOutbidding is the interface to call the smart contract function
1193func (c *Client) AuctionGetOutbidding() (uint16, error) {
1194 c.rw.RLock()
1195 defer c.rw.RUnlock()
1196
1197 log.Error("TODO")
1198 return 0, tracerr.Wrap(errTODO)
1199}
1200
1201// AuctionSetAllocationRatio is the interface to call the smart contract function
1202func (c *Client) AuctionSetAllocationRatio(newAllocationRatio [3]uint16) (tx *types.Transaction, err error) {
1203 c.rw.Lock()
1204 defer c.rw.Unlock()
1205 cpy := c.nextBlock().copy()
1206 defer func() { c.revertIfErr(err, cpy) }()
1207 if c.addr == nil {
1208 return nil, tracerr.Wrap(eth.ErrAccountNil)
1209 }
1210
1211 log.Error("TODO")
1212 return nil, tracerr.Wrap(errTODO)
1213}
1214
1215// AuctionGetAllocationRatio is the interface to call the smart contract function
1216func (c *Client) AuctionGetAllocationRatio() ([3]uint16, error) {
1217 c.rw.RLock()
1218 defer c.rw.RUnlock()
1219
1220 log.Error("TODO")
1221 return [3]uint16{}, tracerr.Wrap(errTODO)
1222}
1223
1224// AuctionSetDonationAddress is the interface to call the smart contract function
1225func (c *Client) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (tx *types.Transaction, err error) {
1226 c.rw.Lock()
1227 defer c.rw.Unlock()
1228 cpy := c.nextBlock().copy()
1229 defer func() { c.revertIfErr(err, cpy) }()
1230 if c.addr == nil {
1231 return nil, tracerr.Wrap(eth.ErrAccountNil)
1232 }
1233
1234 log.Error("TODO")
1235 return nil, tracerr.Wrap(errTODO)
1236}
1237
1238// AuctionGetDonationAddress is the interface to call the smart contract function
1239func (c *Client) AuctionGetDonationAddress() (*ethCommon.Address, error) {
1240 c.rw.RLock()
1241 defer c.rw.RUnlock()
1242
1243 log.Error("TODO")
1244 return nil, tracerr.Wrap(errTODO)
1245}
1246
1247// AuctionSetBootCoordinator is the interface to call the smart contract function
1248func (c *Client) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address, newBootCoordinatorURL string) (tx *types.Transaction, err error) {
1249 c.rw.Lock()
1250 defer c.rw.Unlock()
1251 cpy := c.nextBlock().copy()
1252 defer func() { c.revertIfErr(err, cpy) }()
1253 if c.addr == nil {
1254 return nil, tracerr.Wrap(eth.ErrAccountNil)
1255 }
1256
1257 log.Error("TODO")
1258 return nil, tracerr.Wrap(errTODO)
1259}
1260
1261// AuctionGetBootCoordinator is the interface to call the smart contract function
1262func (c *Client) AuctionGetBootCoordinator() (*ethCommon.Address, error) {
1263 c.rw.RLock()
1264 defer c.rw.RUnlock()
1265
1266 currentBlock := c.currentBlock()
1267 a := currentBlock.Auction
1268
1269 return &a.Vars.BootCoordinator, nil
1270}
1271
1272// AuctionChangeDefaultSlotSetBid is the interface to call the smart contract function
1273func (c *Client) AuctionChangeDefaultSlotSetBid(slotSet int64, newInitialMinBid *big.Int) (tx *types.Transaction, err error) {
1274 c.rw.Lock()
1275 defer c.rw.Unlock()
1276 cpy := c.nextBlock().copy()
1277 defer func() { c.revertIfErr(err, cpy) }()
1278 if c.addr == nil {
1279 return nil, tracerr.Wrap(eth.ErrAccountNil)
1280 }
1281
1282 log.Error("TODO")
1283 return nil, tracerr.Wrap(errTODO)
1284}
1285
1286// AuctionSetCoordinator is the interface to call the smart contract function
1287func (c *Client) AuctionSetCoordinator(forger ethCommon.Address, URL string) (tx *types.Transaction, err error) {
1288 c.rw.Lock()
1289 defer c.rw.Unlock()
1290 cpy := c.nextBlock().copy()
1291 defer func() { c.revertIfErr(err, cpy) }()
1292 if c.addr == nil {
1293 return nil, tracerr.Wrap(eth.ErrAccountNil)
1294 }
1295
1296 nextBlock := c.nextBlock()
1297 a := nextBlock.Auction
1298
1299 a.State.Coordinators[*c.addr] = ð.Coordinator{
1300 Forger: forger,
1301 URL: URL,
1302 }
1303
1304 a.Events.SetCoordinator = append(a.Events.SetCoordinator,
1305 eth.AuctionEventSetCoordinator{
1306 BidderAddress: *c.addr,
1307 ForgerAddress: forger,
1308 CoordinatorURL: URL,
1309 })
1310
1311 type data struct {
1312 BidderAddress ethCommon.Address
1313 ForgerAddress ethCommon.Address
1314 URL string
1315 }
1316 return a.addTransaction(c.newTransaction("registercoordinator", data{*c.addr, forger, URL})), nil
1317}
1318
1319// AuctionIsRegisteredCoordinator is the interface to call the smart contract function
1320func (c *Client) AuctionIsRegisteredCoordinator(forgerAddress ethCommon.Address) (bool, error) {
1321 c.rw.RLock()
1322 defer c.rw.RUnlock()
1323
1324 log.Error("TODO")
1325 return false, tracerr.Wrap(errTODO)
1326}
1327
1328// AuctionUpdateCoordinatorInfo is the interface to call the smart contract function
1329func (c *Client) AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (tx *types.Transaction, err error) {
1330 c.rw.Lock()
1331 defer c.rw.Unlock()
1332 cpy := c.nextBlock().copy()
1333 defer func() { c.revertIfErr(err, cpy) }()
1334 if c.addr == nil {
1335 return nil, tracerr.Wrap(eth.ErrAccountNil)
1336 }
1337
1338 log.Error("TODO")
1339 return nil, tracerr.Wrap(errTODO)
1340}
1341
1342// AuctionGetSlotNumber is the interface to call the smart contract function
1343func (c *Client) AuctionGetSlotNumber(blockNum int64) (int64, error) {
1344 c.rw.RLock()
1345 defer c.rw.RUnlock()
1346
1347 currentBlock := c.currentBlock()
1348 a := currentBlock.Auction
1349 return a.getSlotNumber(blockNum), nil
1350}
1351
1352// AuctionGetCurrentSlotNumber is the interface to call the smart contract function
1353func (c *Client) AuctionGetCurrentSlotNumber() (int64, error) {
1354 c.rw.RLock()
1355 defer c.rw.RUnlock()
1356
1357 log.Error("TODO")
1358 return 0, tracerr.Wrap(errTODO)
1359}
1360
1361// AuctionGetMinBidBySlot is the interface to call the smart contract function
1362func (c *Client) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) {
1363 c.rw.RLock()
1364 defer c.rw.RUnlock()
1365
1366 log.Error("TODO")
1367 return nil, tracerr.Wrap(errTODO)
1368}
1369
1370// AuctionGetDefaultSlotSetBid is the interface to call the smart contract function
1371func (c *Client) AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, error) {
1372 c.rw.RLock()
1373 defer c.rw.RUnlock()
1374
1375 log.Error("TODO")
1376 return nil, tracerr.Wrap(errTODO)
1377}
1378
1379// AuctionGetSlotSet is the interface to call the smart contract function
1380func (c *Client) AuctionGetSlotSet(slot int64) (*big.Int, error) {
1381 c.rw.RLock()
1382 defer c.rw.RUnlock()
1383
1384 log.Error("TODO")
1385 return nil, tracerr.Wrap(errTODO)
1386}
1387
1388// AuctionTokensReceived is the interface to call the smart contract function
1389// func (c *Client) AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, userData, operatorData []byte) error {
1390// return errTODO
1391// }
1392
1393// AuctionBidSimple is a wrapper around AuctionBid that automatically sets `amount` and `deadline`.
1394func (c *Client) AuctionBidSimple(slot int64, bidAmount *big.Int) (tx *types.Transaction, err error) {
1395 return c.AuctionBid(bidAmount, slot, bidAmount, big.NewInt(99999)) //nolint:gomnd
1396}
1397
1398// AuctionBid is the interface to call the smart contract function. This
1399// implementation behaves as if any address has infinite tokens.
1400func (c *Client) AuctionBid(amount *big.Int, slot int64, bidAmount *big.Int,
1401 deadline *big.Int) (tx *types.Transaction, err error) {
1402 c.rw.Lock()
1403 defer c.rw.Unlock()
1404 cpy := c.nextBlock().copy()
1405 defer func() { func() { c.revertIfErr(err, cpy) }() }()
1406 if c.addr == nil {
1407 return nil, tracerr.Wrap(eth.ErrAccountNil)
1408 }
1409
1410 nextBlock := c.nextBlock()
1411 a := nextBlock.Auction
1412
1413 if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
1414 return nil, tracerr.Wrap(errBidClosed)
1415 }
1416
1417 if slot >= a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots)+int64(a.Vars.OpenAuctionSlots) {
1418 return nil, tracerr.Wrap(errBidNotOpen)
1419 }
1420
1421 minBid, err := a.getMinBidBySlot(slot)
1422 if err != nil {
1423 return nil, tracerr.Wrap(err)
1424 }
1425 if bidAmount.Cmp(minBid) == -1 {
1426 return nil, tracerr.Wrap(errBidBelowMin)
1427 }
1428
1429 if _, ok := a.State.Coordinators[*c.addr]; !ok {
1430 return nil, tracerr.Wrap(errCoordNotReg)
1431 }
1432
1433 slotState, ok := a.State.Slots[slot]
1434 if !ok {
1435 slotState = eth.NewSlotState()
1436 a.State.Slots[slot] = slotState
1437 }
1438 slotState.Bidder = *c.addr
1439 slotState.BidAmount = bidAmount
1440
1441 a.Events.NewBid = append(a.Events.NewBid,
1442 eth.AuctionEventNewBid{Slot: slot, BidAmount: bidAmount, Bidder: *c.addr})
1443
1444 type data struct {
1445 Slot int64
1446 BidAmount *big.Int
1447 Bidder ethCommon.Address
1448 }
1449 return a.addTransaction(c.newTransaction("bid", data{slot, bidAmount, *c.addr})), nil
1450}
1451
1452// AuctionMultiBid is the interface to call the smart contract function. This
1453// implementation behaves as if any address has infinite tokens.
1454func (c *Client) AuctionMultiBid(amount *big.Int, startingSlot int64, endingSlot int64, slotSet [6]bool,
1455 maxBid, closedMinBid, deadline *big.Int) (tx *types.Transaction, err error) {
1456 c.rw.Lock()
1457 defer c.rw.Unlock()
1458 cpy := c.nextBlock().copy()
1459 defer func() { c.revertIfErr(err, cpy) }()
1460 if c.addr == nil {
1461 return nil, tracerr.Wrap(eth.ErrAccountNil)
1462 }
1463
1464 log.Error("TODO")
1465 return nil, tracerr.Wrap(errTODO)
1466}
1467
1468// AuctionCanForge is the interface to call the smart contract function
1469func (c *Client) AuctionCanForge(forger ethCommon.Address, blockNum int64) (bool, error) {
1470 c.rw.RLock()
1471 defer c.rw.RUnlock()
1472
1473 currentBlock := c.currentBlock()
1474 a := currentBlock.Auction
1475 return a.canForge(forger, blockNum)
1476}
1477
1478// AuctionForge is the interface to call the smart contract function
1479func (c *Client) AuctionForge(forger ethCommon.Address) (tx *types.Transaction, err error) {
1480 c.rw.Lock()
1481 defer c.rw.Unlock()
1482 cpy := c.nextBlock().copy()
1483 defer func() { c.revertIfErr(err, cpy) }()
1484 if c.addr == nil {
1485 return nil, tracerr.Wrap(eth.ErrAccountNil)
1486 }
1487
1488 log.Error("TODO")
1489 return nil, tracerr.Wrap(errTODO)
1490}
1491
1492// AuctionClaimHEZ is the interface to call the smart contract function
1493func (c *Client) AuctionClaimHEZ() (tx *types.Transaction, err error) {
1494 c.rw.Lock()
1495 defer c.rw.Unlock()
1496 cpy := c.nextBlock().copy()
1497 defer func() { c.revertIfErr(err, cpy) }()
1498 if c.addr == nil {
1499 return nil, tracerr.Wrap(eth.ErrAccountNil)
1500 }
1501
1502 log.Error("TODO")
1503 return nil, tracerr.Wrap(errTODO)
1504}
1505
1506// AuctionGetClaimableHEZ is the interface to call the smart contract function
1507func (c *Client) AuctionGetClaimableHEZ(bidder ethCommon.Address) (*big.Int, error) {
1508 c.rw.RLock()
1509 defer c.rw.RUnlock()
1510
1511 log.Error("TODO")
1512 return nil, tracerr.Wrap(errTODO)
1513}
1514
1515// AuctionConstants returns the Constants of the Auction Smart Contract
1516func (c *Client) AuctionConstants() (*common.AuctionConstants, error) {
1517 c.rw.RLock()
1518 defer c.rw.RUnlock()
1519
1520 return c.auctionConstants, nil
1521}
1522
1523// AuctionEventsByBlock returns the events in a block that happened in the Auction Smart Contract
1524func (c *Client) AuctionEventsByBlock(blockNum int64) (*eth.AuctionEvents, *ethCommon.Hash, error) {
1525 c.rw.RLock()
1526 defer c.rw.RUnlock()
1527
1528 block, ok := c.blocks[blockNum]
1529 if !ok {
1530 return nil, nil, tracerr.Wrap(fmt.Errorf("Block %v doesn't exist", blockNum))
1531 }
1532 return &block.Auction.Events, &block.Eth.Hash, nil
1533}
1534
1535// AuctionEventInit returns the initialize event with its corresponding block number
1536func (c *Client) AuctionEventInit() (*eth.AuctionEventInitialize, int64, error) {
1537 vars := c.blocks[0].Auction.Vars
1538 return ð.AuctionEventInitialize{
1539 DonationAddress: vars.DonationAddress,
1540 BootCoordinatorAddress: vars.BootCoordinator,
1541 BootCoordinatorURL: vars.BootCoordinatorURL,
1542 Outbidding: vars.Outbidding,
1543 SlotDeadline: vars.SlotDeadline,
1544 ClosedAuctionSlots: vars.ClosedAuctionSlots,
1545 OpenAuctionSlots: vars.OpenAuctionSlots,
1546 AllocationRatio: vars.AllocationRatio,
1547 }, 1, nil
1548}
1549
1550//
1551// WDelayer
1552//
1553
1554// WDelayerGetHermezGovernanceAddress is the interface to call the smart contract function
1555func (c *Client) WDelayerGetHermezGovernanceAddress() (*ethCommon.Address, error) {
1556 c.rw.RLock()
1557 defer c.rw.RUnlock()
1558
1559 log.Error("TODO")
1560 return nil, tracerr.Wrap(errTODO)
1561}
1562
1563// WDelayerTransferGovernance is the interface to call the smart contract function
1564func (c *Client) WDelayerTransferGovernance(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
1565 c.rw.Lock()
1566 defer c.rw.Unlock()
1567 cpy := c.nextBlock().copy()
1568 defer func() { c.revertIfErr(err, cpy) }()
1569 if c.addr == nil {
1570 return nil, tracerr.Wrap(eth.ErrAccountNil)
1571 }
1572
1573 log.Error("TODO")
1574 return nil, tracerr.Wrap(errTODO)
1575}
1576
1577// WDelayerClaimGovernance is the interface to call the smart contract function
1578func (c *Client) WDelayerClaimGovernance() (tx *types.Transaction, err error) {
1579 c.rw.Lock()
1580 defer c.rw.Unlock()
1581 cpy := c.nextBlock().copy()
1582 defer func() { c.revertIfErr(err, cpy) }()
1583 if c.addr == nil {
1584 return nil, tracerr.Wrap(eth.ErrAccountNil)
1585 }
1586
1587 log.Error("TODO")
1588 return nil, tracerr.Wrap(errTODO)
1589}
1590
1591// WDelayerGetEmergencyCouncil is the interface to call the smart contract function
1592func (c *Client) WDelayerGetEmergencyCouncil() (*ethCommon.Address, error) {
1593 c.rw.RLock()
1594 defer c.rw.RUnlock()
1595
1596 log.Error("TODO")
1597 return nil, tracerr.Wrap(errTODO)
1598}
1599
1600// WDelayerTransferEmergencyCouncil is the interface to call the smart contract function
1601func (c *Client) WDelayerTransferEmergencyCouncil(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
1602 c.rw.Lock()
1603 defer c.rw.Unlock()
1604 cpy := c.nextBlock().copy()
1605 defer func() { c.revertIfErr(err, cpy) }()
1606 if c.addr == nil {
1607 return nil, tracerr.Wrap(eth.ErrAccountNil)
1608 }
1609
1610 log.Error("TODO")
1611 return nil, tracerr.Wrap(errTODO)
1612}
1613
1614// WDelayerClaimEmergencyCouncil is the interface to call the smart contract function
1615func (c *Client) WDelayerClaimEmergencyCouncil() (tx *types.Transaction, err error) {
1616 c.rw.Lock()
1617 defer c.rw.Unlock()
1618 cpy := c.nextBlock().copy()
1619 defer func() { c.revertIfErr(err, cpy) }()
1620 if c.addr == nil {
1621 return nil, tracerr.Wrap(eth.ErrAccountNil)
1622 }
1623
1624 log.Error("TODO")
1625 return nil, tracerr.Wrap(errTODO)
1626}
1627
1628// WDelayerIsEmergencyMode is the interface to call the smart contract function
1629func (c *Client) WDelayerIsEmergencyMode() (bool, error) {
1630 c.rw.RLock()
1631 defer c.rw.RUnlock()
1632
1633 log.Error("TODO")
1634 return false, tracerr.Wrap(errTODO)
1635}
1636
1637// WDelayerGetWithdrawalDelay is the interface to call the smart contract function
1638func (c *Client) WDelayerGetWithdrawalDelay() (int64, error) {
1639 c.rw.RLock()
1640 defer c.rw.RUnlock()
1641
1642 log.Error("TODO")
1643 return 0, tracerr.Wrap(errTODO)
1644}
1645
1646// WDelayerGetEmergencyModeStartingTime is the interface to call the smart contract function
1647func (c *Client) WDelayerGetEmergencyModeStartingTime() (int64, error) {
1648 c.rw.RLock()
1649 defer c.rw.RUnlock()
1650
1651 log.Error("TODO")
1652 return 0, tracerr.Wrap(errTODO)
1653}
1654
1655// WDelayerEnableEmergencyMode is the interface to call the smart contract function
1656func (c *Client) WDelayerEnableEmergencyMode() (tx *types.Transaction, err error) {
1657 c.rw.Lock()
1658 defer c.rw.Unlock()
1659 cpy := c.nextBlock().copy()
1660 defer func() { c.revertIfErr(err, cpy) }()
1661 if c.addr == nil {
1662 return nil, tracerr.Wrap(eth.ErrAccountNil)
1663 }
1664
1665 log.Error("TODO")
1666 return nil, tracerr.Wrap(errTODO)
1667}
1668
1669// WDelayerChangeWithdrawalDelay is the interface to call the smart contract function
1670func (c *Client) WDelayerChangeWithdrawalDelay(newWithdrawalDelay uint64) (tx *types.Transaction, err error) {
1671 c.rw.Lock()
1672 defer c.rw.Unlock()
1673 cpy := c.nextBlock().copy()
1674 defer func() { c.revertIfErr(err, cpy) }()
1675 if c.addr == nil {
1676 return nil, tracerr.Wrap(eth.ErrAccountNil)
1677 }
1678
1679 nextBlock := c.nextBlock()
1680 w := nextBlock.WDelayer
1681 w.Vars.WithdrawalDelay = newWithdrawalDelay
1682 w.Events.NewWithdrawalDelay = append(w.Events.NewWithdrawalDelay,
1683 eth.WDelayerEventNewWithdrawalDelay{WithdrawalDelay: newWithdrawalDelay})
1684
1685 return w.addTransaction(c.newTransaction("changeWithdrawalDelay", newWithdrawalDelay)), nil
1686}
1687
1688// WDelayerDepositInfo is the interface to call the smart contract function
1689func (c *Client) WDelayerDepositInfo(owner, token ethCommon.Address) (eth.DepositState, error) {
1690 c.rw.RLock()
1691 defer c.rw.RUnlock()
1692
1693 log.Error("TODO")
1694 return eth.DepositState{}, tracerr.Wrap(errTODO)
1695}
1696
1697// WDelayerDeposit is the interface to call the smart contract function
1698func (c *Client) WDelayerDeposit(onwer, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
1699 c.rw.Lock()
1700 defer c.rw.Unlock()
1701 cpy := c.nextBlock().copy()
1702 defer func() { c.revertIfErr(err, cpy) }()
1703 if c.addr == nil {
1704 return nil, tracerr.Wrap(eth.ErrAccountNil)
1705 }
1706
1707 log.Error("TODO")
1708 return nil, tracerr.Wrap(errTODO)
1709}
1710
1711// WDelayerWithdrawal is the interface to call the smart contract function
1712func (c *Client) WDelayerWithdrawal(owner, token ethCommon.Address) (tx *types.Transaction, err error) {
1713 c.rw.Lock()
1714 defer c.rw.Unlock()
1715 cpy := c.nextBlock().copy()
1716 defer func() { c.revertIfErr(err, cpy) }()
1717 if c.addr == nil {
1718 return nil, tracerr.Wrap(eth.ErrAccountNil)
1719 }
1720
1721 log.Error("TODO")
1722 return nil, tracerr.Wrap(errTODO)
1723}
1724
1725// WDelayerEscapeHatchWithdrawal is the interface to call the smart contract function
1726func (c *Client) WDelayerEscapeHatchWithdrawal(to, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
1727 c.rw.Lock()
1728 defer c.rw.Unlock()
1729 cpy := c.nextBlock().copy()
1730 defer func() { c.revertIfErr(err, cpy) }()
1731 if c.addr == nil {
1732 return nil, tracerr.Wrap(eth.ErrAccountNil)
1733 }
1734
1735 log.Error("TODO")
1736 return nil, tracerr.Wrap(errTODO)
1737}
1738
1739// WDelayerEventsByBlock returns the events in a block that happened in the WDelayer Contract
1740func (c *Client) WDelayerEventsByBlock(blockNum int64) (*eth.WDelayerEvents, *ethCommon.Hash, error) {
1741 c.rw.RLock()
1742 defer c.rw.RUnlock()
1743
1744 block, ok := c.blocks[blockNum]
1745 if !ok {
1746 return nil, nil, tracerr.Wrap(fmt.Errorf("Block %v doesn't exist", blockNum))
1747 }
1748 return &block.WDelayer.Events, &block.Eth.Hash, nil
1749}
1750
1751// WDelayerConstants returns the Constants of the WDelayer Contract
1752func (c *Client) WDelayerConstants() (*common.WDelayerConstants, error) {
1753 c.rw.RLock()
1754 defer c.rw.RUnlock()
1755
1756 return c.wDelayerConstants, nil
1757}
1758
1759// WDelayerEventInit returns the initialize event with its corresponding block number
1760func (c *Client) WDelayerEventInit() (*eth.WDelayerEventInitialize, int64, error) {
1761 vars := c.blocks[0].WDelayer.Vars
1762 return ð.WDelayerEventInitialize{
1763 InitialWithdrawalDelay: vars.WithdrawalDelay,
1764 InitialHermezGovernanceAddress: vars.HermezGovernanceAddress,
1765 InitialEmergencyCouncil: vars.EmergencyCouncilAddress,
1766 }, 1, nil
1767}
1768
1769// CtlAddBlocks adds block data to the smarts contracts. The added blocks will
1770// appear as mined. Not thread safe.
1771func (c *Client) CtlAddBlocks(blocks []common.BlockData) (err error) {
1772 // NOTE: We don't lock because internally we call public functions that
1773 // lock already.
1774 for _, block := range blocks {
1775 nextBlock := c.nextBlock()
1776 rollup := nextBlock.Rollup
1777 auction := nextBlock.Auction
1778 for _, token := range block.Rollup.AddedTokens {
1779 if _, err := c.RollupAddTokenSimple(token.EthAddr, rollup.Vars.FeeAddToken); err != nil {
1780 return err
1781 }
1782 }
1783 for _, tx := range block.Rollup.L1UserTxs {
1784 c.CtlSetAddr(tx.FromEthAddr)
1785 if _, err := c.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.DepositAmount, tx.Amount,
1786 uint32(tx.TokenID), int64(tx.ToIdx)); err != nil {
1787 return err
1788 }
1789 }
1790 c.CtlSetAddr(auction.Vars.BootCoordinator)
1791 for _, batch := range block.Rollup.Batches {
1792 if _, err := c.RollupForgeBatch(ð.RollupForgeBatchArgs{
1793 NewLastIdx: batch.Batch.LastIdx,
1794 NewStRoot: batch.Batch.StateRoot,
1795 NewExitRoot: batch.Batch.ExitRoot,
1796 L1CoordinatorTxs: batch.L1CoordinatorTxs,
1797 L1CoordinatorTxsAuths: [][]byte{}, // Intentionally empty
1798 L2TxsData: batch.L2Txs,
1799 FeeIdxCoordinator: batch.Batch.FeeIdxsCoordinator,
1800 // Circuit selector
1801 VerifierIdx: 0, // Intentionally empty
1802 L1Batch: batch.L1Batch,
1803 ProofA: [2]*big.Int{}, // Intentionally empty
1804 ProofB: [2][2]*big.Int{}, // Intentionally empty
1805 ProofC: [2]*big.Int{}, // Intentionally empty
1806 }); err != nil {
1807 return err
1808 }
1809 }
1810 // Mine block and sync
1811 c.CtlMineBlock()
1812 }
1813 return nil
1814}