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