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