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