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