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