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