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