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() int64 {
557 c.rw.RLock()
558 defer c.rw.RUnlock()
559 return c.blockNum
560}
561
562// EthLastBlock returns the last blockNum
563func (c *Client) EthLastBlock() (int64, error) {
564 c.rw.RLock()
565 defer c.rw.RUnlock()
566
567 if c.blockNum < c.maxBlockNum {
568 panic("blockNum has decreased. " +
569 "After a rollback you must mine to reach the same or higher blockNum")
570 }
571 return c.blockNum, nil
572}
573
574// EthTransactionReceipt returns the transaction receipt of the given txHash
575func (c *Client) EthTransactionReceipt(ctx context.Context, txHash ethCommon.Hash) (*types.Receipt, error) {
576 c.rw.RLock()
577 defer c.rw.RUnlock()
578
579 for i := int64(0); i < c.blockNum; i++ {
580 b := c.blocks[i]
581 _, ok := b.Rollup.Txs[txHash]
582 if !ok {
583 _, ok = b.Auction.Txs[txHash]
584 }
585 if ok {
586 return &types.Receipt{
587 TxHash: txHash,
588 Status: types.ReceiptStatusSuccessful,
589 BlockHash: b.Eth.Hash,
590 BlockNumber: big.NewInt(b.Eth.BlockNum),
591 }, nil
592 }
593 }
594
595 return nil, nil
596}
597
598// CtlAddERC20 adds an ERC20 token to the blockchain.
599func (c *Client) CtlAddERC20(tokenAddr ethCommon.Address, constants eth.ERC20Consts) {
600 nextBlock := c.nextBlock()
601 e := nextBlock.Eth
602 e.Tokens[tokenAddr] = constants
603}
604
605// EthERC20Consts returns the constants defined for a particular ERC20 Token instance.
606func (c *Client) EthERC20Consts(tokenAddr ethCommon.Address) (*eth.ERC20Consts, error) {
607 currentBlock := c.currentBlock()
608 e := currentBlock.Eth
609 if constants, ok := e.Tokens[tokenAddr]; ok {
610 return &constants, nil
611 }
612 return nil, fmt.Errorf("tokenAddr not found")
613}
614
615// func newHeader(number *big.Int) *types.Header {
616// return &types.Header{
617// Number: number,
618// Time: uint64(number.Int64()),
619// }
620// }
621
622// EthHeaderByNumber returns the *types.Header for the given block number in a
623// deterministic way.
624// func (c *Client) EthHeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
625// return newHeader(number), nil
626// }
627
628// EthBlockByNumber returns the *common.Block for the given block number in a
629// deterministic way.
630func (c *Client) EthBlockByNumber(ctx context.Context, blockNum int64) (*common.Block, error) {
631 c.rw.RLock()
632 defer c.rw.RUnlock()
633
634 if blockNum > c.blockNum {
635 return nil, ethereum.NotFound
636 }
637 block := c.blocks[blockNum]
638 return &common.Block{
639 EthBlockNum: blockNum,
640 Timestamp: time.Unix(block.Eth.Time, 0),
641 Hash: block.Eth.Hash,
642 ParentHash: block.Eth.ParentHash,
643 }, nil
644}
645
646// EthAddress returns the ethereum address of the account loaded into the Client
647func (c *Client) EthAddress() (*ethCommon.Address, error) {
648 if c.addr == nil {
649 return nil, eth.ErrAccountNil
650 }
651 return c.addr, nil
652}
653
654var errTODO = fmt.Errorf("TODO: Not implemented yet")
655
656//
657// Rollup
658//
659
660// CtlAddL1TxUser adds an L1TxUser to the L1UserTxs queue of the Rollup
661// func (c *Client) CtlAddL1TxUser(l1Tx *common.L1Tx) {
662// c.rw.Lock()
663// defer c.rw.Unlock()
664//
665// nextBlock := c.nextBlock()
666// r := nextBlock.Rollup
667// queue := r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
668// if len(queue.L1TxQueue) >= eth.RollupConstMaxL1UserTx {
669// r.State.LastToForgeL1TxsNum++
670// r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
671// queue = r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
672// }
673// if int64(l1Tx.FromIdx) > r.State.CurrentIdx {
674// panic("l1Tx.FromIdx > r.State.CurrentIdx")
675// }
676// if int(l1Tx.TokenID)+1 > len(r.State.TokenList) {
677// panic("l1Tx.TokenID + 1 > len(r.State.TokenList)")
678// }
679// queue.L1TxQueue = append(queue.L1TxQueue, *l1Tx)
680// r.Events.L1UserTx = append(r.Events.L1UserTx, eth.RollupEventL1UserTx{
681// L1Tx: *l1Tx,
682// ToForgeL1TxsNum: r.State.LastToForgeL1TxsNum,
683// Position: len(queue.L1TxQueue) - 1,
684// })
685// }
686
687// RollupL1UserTxERC20Permit is the interface to call the smart contract function
688func (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) {
689 log.Error("TODO")
690 return nil, errTODO
691}
692
693// RollupL1UserTxERC20ETH sends an L1UserTx to the Rollup.
694func (c *Client) RollupL1UserTxERC20ETH(
695 fromBJJ *babyjub.PublicKey,
696 fromIdx int64,
697 loadAmount *big.Int,
698 amount *big.Int,
699 tokenID uint32,
700 toIdx int64,
701) (tx *types.Transaction, err error) {
702 c.rw.Lock()
703 defer c.rw.Unlock()
704 cpy := c.nextBlock().copy()
705 defer func() { c.revertIfErr(err, cpy) }()
706
707 _, err = common.NewFloat16(amount)
708 if err != nil {
709 return nil, err
710 }
711 _, err = common.NewFloat16(loadAmount)
712 if err != nil {
713 return nil, err
714 }
715
716 nextBlock := c.nextBlock()
717 r := nextBlock.Rollup
718 queue := r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
719 if len(queue.L1TxQueue) >= common.RollupConstMaxL1UserTx {
720 r.State.LastToForgeL1TxsNum++
721 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
722 queue = r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
723 }
724 if fromIdx > r.State.CurrentIdx {
725 panic("l1Tx.FromIdx > r.State.CurrentIdx")
726 }
727 if int(tokenID)+1 > len(r.State.TokenList) {
728 panic("l1Tx.TokenID + 1 > len(r.State.TokenList)")
729 }
730 toForgeL1TxsNum := r.State.LastToForgeL1TxsNum
731 l1Tx, err := common.NewL1Tx(&common.L1Tx{
732 FromIdx: common.Idx(fromIdx),
733 FromEthAddr: *c.addr,
734 FromBJJ: fromBJJ,
735 Amount: amount,
736 LoadAmount: loadAmount,
737 TokenID: common.TokenID(tokenID),
738 ToIdx: common.Idx(toIdx),
739 ToForgeL1TxsNum: &toForgeL1TxsNum,
740 Position: len(queue.L1TxQueue),
741 UserOrigin: true,
742 })
743 if err != nil {
744 return nil, err
745 }
746
747 queue.L1TxQueue = append(queue.L1TxQueue, *l1Tx)
748 r.Events.L1UserTx = append(r.Events.L1UserTx, eth.RollupEventL1UserTx{
749 L1UserTx: *l1Tx,
750 })
751 return r.addTransaction(newTransaction("l1UserTxERC20ETH", l1Tx)), nil
752}
753
754// RollupL1UserTxERC777 is the interface to call the smart contract function
755// func (c *Client) RollupL1UserTxERC777(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error) {
756// log.Error("TODO")
757// return nil, errTODO
758// }
759
760// RollupRegisterTokensCount is the interface to call the smart contract function
761func (c *Client) RollupRegisterTokensCount() (*big.Int, error) {
762 log.Error("TODO")
763 return nil, errTODO
764}
765
766// RollupLastForgedBatch is the interface to call the smart contract function
767func (c *Client) RollupLastForgedBatch() (int64, error) {
768 c.rw.RLock()
769 defer c.rw.RUnlock()
770
771 currentBlock := c.currentBlock()
772 e := currentBlock.Rollup
773 return int64(len(e.State.ExitRoots)) - 1, nil
774}
775
776// RollupWithdrawCircuit is the interface to call the smart contract function
777func (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) {
778 log.Error("TODO")
779 return nil, errTODO
780}
781
782// RollupWithdrawMerkleProof is the interface to call the smart contract function
783func (c *Client) RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) {
784 c.rw.Lock()
785 defer c.rw.Unlock()
786 cpy := c.nextBlock().copy()
787 defer func() { c.revertIfErr(err, cpy) }()
788
789 nextBlock := c.nextBlock()
790 r := nextBlock.Rollup
791
792 if int(numExitRoot) >= len(r.State.ExitRoots) {
793 return nil, fmt.Errorf("numExitRoot >= len(r.State.ExitRoots)")
794 }
795 if _, ok := r.State.ExitNullifierMap[numExitRoot][idx]; ok {
796 return nil, fmt.Errorf("exit already withdrawn")
797 }
798 r.State.ExitNullifierMap[numExitRoot][idx] = true
799
800 type data struct {
801 BabyPubKey *babyjub.PublicKey
802 TokenID uint32
803 NumExitRoot int64
804 Idx int64
805 Amount *big.Int
806 Siblings []*big.Int
807 InstantWithdraw bool
808 }
809 tx = r.addTransaction(newTransaction("withdrawMerkleProof", data{
810 BabyPubKey: babyPubKey,
811 TokenID: tokenID,
812 NumExitRoot: numExitRoot,
813 Idx: idx,
814 Amount: amount,
815 Siblings: siblings,
816 InstantWithdraw: instantWithdraw,
817 }))
818 r.Events.Withdraw = append(r.Events.Withdraw, eth.RollupEventWithdraw{
819 Idx: uint64(idx),
820 NumExitRoot: uint64(numExitRoot),
821 InstantWithdraw: instantWithdraw,
822 TxHash: tx.Hash(),
823 })
824
825 if !instantWithdraw {
826 w := nextBlock.WDelayer
827 w.deposit(tx.Hash(), *c.addr, r.State.TokenList[int(tokenID)], amount)
828 }
829 return tx, nil
830}
831
832type transactionData struct {
833 Name string
834 Value interface{}
835}
836
837func newTransaction(name string, value interface{}) *types.Transaction {
838 data, err := json.Marshal(transactionData{name, value})
839 if err != nil {
840 panic(err)
841 }
842 return types.NewTransaction(0, ethCommon.Address{}, nil, 0, nil,
843 data)
844}
845
846// RollupForgeBatch is the interface to call the smart contract function
847func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs) (tx *types.Transaction, err error) {
848 c.rw.Lock()
849 defer c.rw.Unlock()
850 cpy := c.nextBlock().copy()
851 defer func() { c.revertIfErr(err, cpy) }()
852 if c.addr == nil {
853 return nil, eth.ErrAccountNil
854 }
855
856 a := c.nextBlock().Auction
857 ok, err := a.canForge(*c.addr, a.Eth.BlockNum)
858 if err != nil {
859 return nil, err
860 }
861 if !ok {
862 return nil, fmt.Errorf("incorrect slot")
863 }
864
865 // TODO: Verify proof
866
867 // Auction
868 err = a.forge(*c.addr)
869 if err != nil {
870 return nil, err
871 }
872
873 // TODO: If successful, store the tx in a successful array.
874 // TODO: If failed, store the tx in a failed array.
875 // TODO: Add method to move the tx to another block, reapply it there, and possibly go from successful to failed.
876
877 return c.addBatch(args)
878}
879
880// CtlAddBatch adds forged batch to the Rollup, without checking any ZKProof
881func (c *Client) CtlAddBatch(args *eth.RollupForgeBatchArgs) {
882 c.rw.Lock()
883 defer c.rw.Unlock()
884
885 if _, err := c.addBatch(args); err != nil {
886 panic(err)
887 }
888}
889
890func (c *Client) addBatch(args *eth.RollupForgeBatchArgs) (*types.Transaction, error) {
891 nextBlock := c.nextBlock()
892 r := nextBlock.Rollup
893 r.State.StateRoot = args.NewStRoot
894 if args.NewLastIdx < r.State.CurrentIdx {
895 return nil, fmt.Errorf("args.NewLastIdx < r.State.CurrentIdx")
896 }
897 r.State.CurrentIdx = args.NewLastIdx
898 r.State.ExitNullifierMap[int64(len(r.State.ExitRoots))] = make(map[int64]bool)
899 r.State.ExitRoots = append(r.State.ExitRoots, args.NewExitRoot)
900 if args.L1Batch {
901 r.State.CurrentToForgeL1TxsNum++
902 if r.State.CurrentToForgeL1TxsNum == r.State.LastToForgeL1TxsNum {
903 r.State.LastToForgeL1TxsNum++
904 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
905 }
906 }
907 ethTx := r.addTransaction(newTransaction("forgebatch", args))
908 c.forgeBatchArgsPending[ethTx.Hash()] = &batch{*args, *c.addr}
909 r.Events.ForgeBatch = append(r.Events.ForgeBatch, eth.RollupEventForgeBatch{
910 BatchNum: int64(len(r.State.ExitRoots)) - 1,
911 EthTxHash: ethTx.Hash(),
912 })
913
914 return ethTx, nil
915}
916
917// RollupAddTokenSimple is a wrapper around RollupAddToken that automatically
918// sets `deadlie`.
919func (c *Client) RollupAddTokenSimple(tokenAddress ethCommon.Address, feeAddToken *big.Int) (tx *types.Transaction, err error) {
920 return c.RollupAddToken(tokenAddress, feeAddToken, big.NewInt(9999)) //nolint:gomnd
921}
922
923// RollupAddToken is the interface to call the smart contract function
924func (c *Client) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken *big.Int,
925 deadline *big.Int) (tx *types.Transaction, err error) {
926 c.rw.Lock()
927 defer c.rw.Unlock()
928 cpy := c.nextBlock().copy()
929 defer func() { c.revertIfErr(err, cpy) }()
930 if c.addr == nil {
931 return nil, eth.ErrAccountNil
932 }
933
934 nextBlock := c.nextBlock()
935 r := nextBlock.Rollup
936 if _, ok := r.State.TokenMap[tokenAddress]; ok {
937 return nil, fmt.Errorf("Token %v already registered", tokenAddress)
938 }
939 if feeAddToken.Cmp(r.Vars.FeeAddToken) != 0 {
940 return nil, fmt.Errorf("Expected fee: %v but got: %v", r.Vars.FeeAddToken, feeAddToken)
941 }
942
943 r.State.TokenMap[tokenAddress] = true
944 r.State.TokenList = append(r.State.TokenList, tokenAddress)
945 r.Events.AddToken = append(r.Events.AddToken, eth.RollupEventAddToken{TokenAddress: tokenAddress,
946 TokenID: uint32(len(r.State.TokenList) - 1)})
947 return r.addTransaction(newTransaction("addtoken", tokenAddress)), nil
948}
949
950// RollupGetCurrentTokens is the interface to call the smart contract function
951func (c *Client) RollupGetCurrentTokens() (*big.Int, error) {
952 c.rw.RLock()
953 defer c.rw.RUnlock()
954
955 log.Error("TODO")
956 return nil, errTODO
957}
958
959// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
960func (c *Client) RollupUpdateForgeL1L2BatchTimeout(newForgeL1Timeout int64) (tx *types.Transaction, err error) {
961 c.rw.Lock()
962 defer c.rw.Unlock()
963 cpy := c.nextBlock().copy()
964 defer func() { c.revertIfErr(err, cpy) }()
965 if c.addr == nil {
966 return nil, eth.ErrAccountNil
967 }
968
969 nextBlock := c.nextBlock()
970 r := nextBlock.Rollup
971 r.Vars.ForgeL1L2BatchTimeout = newForgeL1Timeout
972 r.Events.UpdateForgeL1L2BatchTimeout = append(r.Events.UpdateForgeL1L2BatchTimeout,
973 eth.RollupEventUpdateForgeL1L2BatchTimeout{NewForgeL1L2BatchTimeout: newForgeL1Timeout})
974
975 return r.addTransaction(newTransaction("updateForgeL1L2BatchTimeout", newForgeL1Timeout)), nil
976}
977
978// RollupUpdateFeeAddToken is the interface to call the smart contract function
979func (c *Client) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
980 c.rw.Lock()
981 defer c.rw.Unlock()
982 cpy := c.nextBlock().copy()
983 defer func() { c.revertIfErr(err, cpy) }()
984 if c.addr == nil {
985 return nil, eth.ErrAccountNil
986 }
987
988 log.Error("TODO")
989 return nil, errTODO
990}
991
992// RollupUpdateTokensHEZ is the interface to call the smart contract function
993// func (c *Client) RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (tx *types.Transaction, err error) {
994// c.rw.Lock()
995// defer c.rw.Unlock()
996// cpy := c.nextBlock().copy()
997// defer func() { c.revertIfErr(err, cpy) }()
998//
999// log.Error("TODO")
1000// return nil, errTODO
1001// }
1002
1003// RollupUpdateGovernance is the interface to call the smart contract function
1004// func (c *Client) RollupUpdateGovernance() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol)
1005// return nil, errTODO
1006// }
1007
1008// RollupConstants returns the Constants of the Rollup Smart Contract
1009func (c *Client) RollupConstants() (*common.RollupConstants, error) {
1010 c.rw.RLock()
1011 defer c.rw.RUnlock()
1012
1013 return c.rollupConstants, nil
1014}
1015
1016// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
1017func (c *Client) RollupEventsByBlock(blockNum int64) (*eth.RollupEvents, *ethCommon.Hash, error) {
1018 c.rw.RLock()
1019 defer c.rw.RUnlock()
1020
1021 block, ok := c.blocks[blockNum]
1022 if !ok {
1023 return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum)
1024 }
1025 return &block.Rollup.Events, &block.Eth.Hash, nil
1026}
1027
1028// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the Rollup Smart Contract in the given transaction
1029func (c *Client) RollupForgeBatchArgs(ethTxHash ethCommon.Hash) (*eth.RollupForgeBatchArgs, *ethCommon.Address, error) {
1030 c.rw.RLock()
1031 defer c.rw.RUnlock()
1032
1033 batch, ok := c.forgeBatchArgs[ethTxHash]
1034 if !ok {
1035 return nil, nil, fmt.Errorf("transaction not found")
1036 }
1037 return &batch.ForgeBatchArgs, &batch.Sender, nil
1038}
1039
1040//
1041// Auction
1042//
1043
1044// AuctionSetSlotDeadline is the interface to call the smart contract function
1045func (c *Client) AuctionSetSlotDeadline(newDeadline uint8) (tx *types.Transaction, err error) {
1046 c.rw.Lock()
1047 defer c.rw.Unlock()
1048 cpy := c.nextBlock().copy()
1049 defer func() { c.revertIfErr(err, cpy) }()
1050 if c.addr == nil {
1051 return nil, eth.ErrAccountNil
1052 }
1053
1054 log.Error("TODO")
1055 return nil, errTODO
1056}
1057
1058// AuctionGetSlotDeadline is the interface to call the smart contract function
1059func (c *Client) AuctionGetSlotDeadline() (uint8, error) {
1060 c.rw.RLock()
1061 defer c.rw.RUnlock()
1062
1063 log.Error("TODO")
1064 return 0, errTODO
1065}
1066
1067// AuctionSetOpenAuctionSlots is the interface to call the smart contract function
1068func (c *Client) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (tx *types.Transaction, err error) {
1069 c.rw.Lock()
1070 defer c.rw.Unlock()
1071 cpy := c.nextBlock().copy()
1072 defer func() { c.revertIfErr(err, cpy) }()
1073 if c.addr == nil {
1074 return nil, eth.ErrAccountNil
1075 }
1076
1077 nextBlock := c.nextBlock()
1078 a := nextBlock.Auction
1079 a.Vars.OpenAuctionSlots = newOpenAuctionSlots
1080 a.Events.NewOpenAuctionSlots = append(a.Events.NewOpenAuctionSlots,
1081 eth.AuctionEventNewOpenAuctionSlots{NewOpenAuctionSlots: newOpenAuctionSlots})
1082
1083 return a.addTransaction(newTransaction("setOpenAuctionSlots", newOpenAuctionSlots)), nil
1084}
1085
1086// AuctionGetOpenAuctionSlots is the interface to call the smart contract function
1087func (c *Client) AuctionGetOpenAuctionSlots() (uint16, error) {
1088 c.rw.RLock()
1089 defer c.rw.RUnlock()
1090
1091 log.Error("TODO")
1092 return 0, errTODO
1093}
1094
1095// AuctionSetClosedAuctionSlots is the interface to call the smart contract function
1096func (c *Client) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (tx *types.Transaction, err error) {
1097 c.rw.Lock()
1098 defer c.rw.Unlock()
1099 cpy := c.nextBlock().copy()
1100 defer func() { c.revertIfErr(err, cpy) }()
1101 if c.addr == nil {
1102 return nil, eth.ErrAccountNil
1103 }
1104
1105 log.Error("TODO")
1106 return nil, errTODO
1107}
1108
1109// AuctionGetClosedAuctionSlots is the interface to call the smart contract function
1110func (c *Client) AuctionGetClosedAuctionSlots() (uint16, error) {
1111 c.rw.RLock()
1112 defer c.rw.RUnlock()
1113
1114 log.Error("TODO")
1115 return 0, errTODO
1116}
1117
1118// AuctionSetOutbidding is the interface to call the smart contract function
1119func (c *Client) AuctionSetOutbidding(newOutbidding uint16) (tx *types.Transaction, err error) {
1120 c.rw.Lock()
1121 defer c.rw.Unlock()
1122 cpy := c.nextBlock().copy()
1123 defer func() { c.revertIfErr(err, cpy) }()
1124 if c.addr == nil {
1125 return nil, eth.ErrAccountNil
1126 }
1127
1128 log.Error("TODO")
1129 return nil, errTODO
1130}
1131
1132// AuctionGetOutbidding is the interface to call the smart contract function
1133func (c *Client) AuctionGetOutbidding() (uint16, error) {
1134 c.rw.RLock()
1135 defer c.rw.RUnlock()
1136
1137 log.Error("TODO")
1138 return 0, errTODO
1139}
1140
1141// AuctionSetAllocationRatio is the interface to call the smart contract function
1142func (c *Client) AuctionSetAllocationRatio(newAllocationRatio [3]uint16) (tx *types.Transaction, err error) {
1143 c.rw.Lock()
1144 defer c.rw.Unlock()
1145 cpy := c.nextBlock().copy()
1146 defer func() { c.revertIfErr(err, cpy) }()
1147 if c.addr == nil {
1148 return nil, eth.ErrAccountNil
1149 }
1150
1151 log.Error("TODO")
1152 return nil, errTODO
1153}
1154
1155// AuctionGetAllocationRatio is the interface to call the smart contract function
1156func (c *Client) AuctionGetAllocationRatio() ([3]uint16, error) {
1157 c.rw.RLock()
1158 defer c.rw.RUnlock()
1159
1160 log.Error("TODO")
1161 return [3]uint16{}, errTODO
1162}
1163
1164// AuctionSetDonationAddress is the interface to call the smart contract function
1165func (c *Client) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (tx *types.Transaction, err error) {
1166 c.rw.Lock()
1167 defer c.rw.Unlock()
1168 cpy := c.nextBlock().copy()
1169 defer func() { c.revertIfErr(err, cpy) }()
1170 if c.addr == nil {
1171 return nil, eth.ErrAccountNil
1172 }
1173
1174 log.Error("TODO")
1175 return nil, errTODO
1176}
1177
1178// AuctionGetDonationAddress is the interface to call the smart contract function
1179func (c *Client) AuctionGetDonationAddress() (*ethCommon.Address, error) {
1180 c.rw.RLock()
1181 defer c.rw.RUnlock()
1182
1183 log.Error("TODO")
1184 return nil, errTODO
1185}
1186
1187// AuctionSetBootCoordinator is the interface to call the smart contract function
1188func (c *Client) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address) (tx *types.Transaction, err error) {
1189 c.rw.Lock()
1190 defer c.rw.Unlock()
1191 cpy := c.nextBlock().copy()
1192 defer func() { c.revertIfErr(err, cpy) }()
1193 if c.addr == nil {
1194 return nil, eth.ErrAccountNil
1195 }
1196
1197 log.Error("TODO")
1198 return nil, errTODO
1199}
1200
1201// AuctionGetBootCoordinator is the interface to call the smart contract function
1202func (c *Client) AuctionGetBootCoordinator() (*ethCommon.Address, error) {
1203 c.rw.RLock()
1204 defer c.rw.RUnlock()
1205
1206 currentBlock := c.currentBlock()
1207 a := currentBlock.Auction
1208
1209 return &a.Vars.BootCoordinator, nil
1210}
1211
1212// AuctionChangeDefaultSlotSetBid is the interface to call the smart contract function
1213func (c *Client) AuctionChangeDefaultSlotSetBid(slotSet int64, newInitialMinBid *big.Int) (tx *types.Transaction, err error) {
1214 c.rw.Lock()
1215 defer c.rw.Unlock()
1216 cpy := c.nextBlock().copy()
1217 defer func() { c.revertIfErr(err, cpy) }()
1218 if c.addr == nil {
1219 return nil, eth.ErrAccountNil
1220 }
1221
1222 log.Error("TODO")
1223 return nil, errTODO
1224}
1225
1226// AuctionSetCoordinator is the interface to call the smart contract function
1227func (c *Client) AuctionSetCoordinator(forger ethCommon.Address, URL string) (tx *types.Transaction, err error) {
1228 c.rw.Lock()
1229 defer c.rw.Unlock()
1230 cpy := c.nextBlock().copy()
1231 defer func() { c.revertIfErr(err, cpy) }()
1232 if c.addr == nil {
1233 return nil, eth.ErrAccountNil
1234 }
1235
1236 nextBlock := c.nextBlock()
1237 a := nextBlock.Auction
1238
1239 a.State.Coordinators[*c.addr] = ð.Coordinator{
1240 Forger: forger,
1241 URL: URL,
1242 }
1243
1244 a.Events.SetCoordinator = append(a.Events.SetCoordinator,
1245 eth.AuctionEventSetCoordinator{
1246 BidderAddress: *c.addr,
1247 ForgerAddress: forger,
1248 CoordinatorURL: URL,
1249 })
1250
1251 type data struct {
1252 BidderAddress ethCommon.Address
1253 ForgerAddress ethCommon.Address
1254 URL string
1255 }
1256 return a.addTransaction(newTransaction("registercoordinator", data{*c.addr, forger, URL})), nil
1257}
1258
1259// AuctionIsRegisteredCoordinator is the interface to call the smart contract function
1260func (c *Client) AuctionIsRegisteredCoordinator(forgerAddress ethCommon.Address) (bool, error) {
1261 c.rw.RLock()
1262 defer c.rw.RUnlock()
1263
1264 log.Error("TODO")
1265 return false, errTODO
1266}
1267
1268// AuctionUpdateCoordinatorInfo is the interface to call the smart contract function
1269func (c *Client) AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (tx *types.Transaction, err error) {
1270 c.rw.Lock()
1271 defer c.rw.Unlock()
1272 cpy := c.nextBlock().copy()
1273 defer func() { c.revertIfErr(err, cpy) }()
1274 if c.addr == nil {
1275 return nil, eth.ErrAccountNil
1276 }
1277
1278 log.Error("TODO")
1279 return nil, errTODO
1280}
1281
1282// AuctionGetSlotNumber is the interface to call the smart contract function
1283func (c *Client) AuctionGetSlotNumber(blockNum int64) (int64, error) {
1284 c.rw.RLock()
1285 defer c.rw.RUnlock()
1286
1287 currentBlock := c.currentBlock()
1288 a := currentBlock.Auction
1289 return a.getSlotNumber(blockNum), nil
1290}
1291
1292// AuctionGetCurrentSlotNumber is the interface to call the smart contract function
1293func (c *Client) AuctionGetCurrentSlotNumber() (int64, error) {
1294 c.rw.RLock()
1295 defer c.rw.RUnlock()
1296
1297 log.Error("TODO")
1298 return 0, errTODO
1299}
1300
1301// AuctionGetMinBidBySlot is the interface to call the smart contract function
1302func (c *Client) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) {
1303 c.rw.RLock()
1304 defer c.rw.RUnlock()
1305
1306 log.Error("TODO")
1307 return nil, errTODO
1308}
1309
1310// AuctionGetDefaultSlotSetBid is the interface to call the smart contract function
1311func (c *Client) AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, error) {
1312 c.rw.RLock()
1313 defer c.rw.RUnlock()
1314
1315 log.Error("TODO")
1316 return nil, errTODO
1317}
1318
1319// AuctionGetSlotSet is the interface to call the smart contract function
1320func (c *Client) AuctionGetSlotSet(slot int64) (*big.Int, error) {
1321 c.rw.RLock()
1322 defer c.rw.RUnlock()
1323
1324 log.Error("TODO")
1325 return nil, errTODO
1326}
1327
1328// AuctionTokensReceived is the interface to call the smart contract function
1329// func (c *Client) AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, userData, operatorData []byte) error {
1330// return errTODO
1331// }
1332
1333// AuctionBidSimple is a wrapper around AuctionBid that automatically sets `amount` and `deadline`.
1334func (c *Client) AuctionBidSimple(slot int64, bidAmount *big.Int) (tx *types.Transaction, err error) {
1335 return c.AuctionBid(bidAmount, slot, bidAmount, big.NewInt(99999)) //nolint:gomnd
1336}
1337
1338// AuctionBid is the interface to call the smart contract function. This
1339// implementation behaves as if any address has infinite tokens.
1340func (c *Client) AuctionBid(amount *big.Int, slot int64, bidAmount *big.Int,
1341 deadline *big.Int) (tx *types.Transaction, err error) {
1342 c.rw.Lock()
1343 defer c.rw.Unlock()
1344 cpy := c.nextBlock().copy()
1345 defer func() { func() { c.revertIfErr(err, cpy) }() }()
1346 if c.addr == nil {
1347 return nil, eth.ErrAccountNil
1348 }
1349
1350 nextBlock := c.nextBlock()
1351 a := nextBlock.Auction
1352
1353 if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
1354 return nil, errBidClosed
1355 }
1356
1357 if slot >= a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots)+int64(a.Vars.OpenAuctionSlots) {
1358 return nil, errBidNotOpen
1359 }
1360
1361 minBid, err := a.getMinBidBySlot(slot)
1362 if err != nil {
1363 return nil, err
1364 }
1365 if bidAmount.Cmp(minBid) == -1 {
1366 return nil, errBidBelowMin
1367 }
1368
1369 if _, ok := a.State.Coordinators[*c.addr]; !ok {
1370 return nil, errCoordNotReg
1371 }
1372
1373 slotState, ok := a.State.Slots[slot]
1374 if !ok {
1375 slotState = eth.NewSlotState()
1376 a.State.Slots[slot] = slotState
1377 }
1378 slotState.Bidder = *c.addr
1379 slotState.BidAmount = bidAmount
1380
1381 a.Events.NewBid = append(a.Events.NewBid,
1382 eth.AuctionEventNewBid{Slot: slot, BidAmount: bidAmount, Bidder: *c.addr})
1383
1384 type data struct {
1385 Slot int64
1386 BidAmount *big.Int
1387 Bidder ethCommon.Address
1388 }
1389 return a.addTransaction(newTransaction("bid", data{slot, bidAmount, *c.addr})), nil
1390}
1391
1392// AuctionMultiBid is the interface to call the smart contract function. This
1393// implementation behaves as if any address has infinite tokens.
1394func (c *Client) AuctionMultiBid(amount *big.Int, startingSlot int64, endingSlot int64, slotSet [6]bool,
1395 maxBid, closedMinBid, deadline *big.Int) (tx *types.Transaction, err error) {
1396 c.rw.Lock()
1397 defer c.rw.Unlock()
1398 cpy := c.nextBlock().copy()
1399 defer func() { c.revertIfErr(err, cpy) }()
1400 if c.addr == nil {
1401 return nil, eth.ErrAccountNil
1402 }
1403
1404 log.Error("TODO")
1405 return nil, errTODO
1406}
1407
1408// AuctionCanForge is the interface to call the smart contract function
1409func (c *Client) AuctionCanForge(forger ethCommon.Address, blockNum int64) (bool, error) {
1410 c.rw.RLock()
1411 defer c.rw.RUnlock()
1412
1413 currentBlock := c.currentBlock()
1414 a := currentBlock.Auction
1415 return a.canForge(forger, blockNum)
1416}
1417
1418// AuctionForge is the interface to call the smart contract function
1419func (c *Client) AuctionForge(forger ethCommon.Address) (tx *types.Transaction, err error) {
1420 c.rw.Lock()
1421 defer c.rw.Unlock()
1422 cpy := c.nextBlock().copy()
1423 defer func() { c.revertIfErr(err, cpy) }()
1424 if c.addr == nil {
1425 return nil, eth.ErrAccountNil
1426 }
1427
1428 log.Error("TODO")
1429 return nil, errTODO
1430}
1431
1432// AuctionClaimHEZ is the interface to call the smart contract function
1433func (c *Client) AuctionClaimHEZ() (tx *types.Transaction, err error) {
1434 c.rw.Lock()
1435 defer c.rw.Unlock()
1436 cpy := c.nextBlock().copy()
1437 defer func() { c.revertIfErr(err, cpy) }()
1438 if c.addr == nil {
1439 return nil, eth.ErrAccountNil
1440 }
1441
1442 log.Error("TODO")
1443 return nil, errTODO
1444}
1445
1446// AuctionGetClaimableHEZ is the interface to call the smart contract function
1447func (c *Client) AuctionGetClaimableHEZ(bidder ethCommon.Address) (*big.Int, error) {
1448 c.rw.RLock()
1449 defer c.rw.RUnlock()
1450
1451 log.Error("TODO")
1452 return nil, errTODO
1453}
1454
1455// AuctionConstants returns the Constants of the Auction Smart Contract
1456func (c *Client) AuctionConstants() (*common.AuctionConstants, error) {
1457 c.rw.RLock()
1458 defer c.rw.RUnlock()
1459
1460 return c.auctionConstants, nil
1461}
1462
1463// AuctionEventsByBlock returns the events in a block that happened in the Auction Smart Contract
1464func (c *Client) AuctionEventsByBlock(blockNum int64) (*eth.AuctionEvents, *ethCommon.Hash, error) {
1465 c.rw.RLock()
1466 defer c.rw.RUnlock()
1467
1468 block, ok := c.blocks[blockNum]
1469 if !ok {
1470 return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum)
1471 }
1472 return &block.Auction.Events, &block.Eth.Hash, nil
1473}
1474
1475//
1476// WDelayer
1477//
1478
1479// WDelayerGetHermezGovernanceDAOAddress is the interface to call the smart contract function
1480func (c *Client) WDelayerGetHermezGovernanceDAOAddress() (*ethCommon.Address, error) {
1481 c.rw.RLock()
1482 defer c.rw.RUnlock()
1483
1484 log.Error("TODO")
1485 return nil, errTODO
1486}
1487
1488// WDelayerSetHermezGovernanceDAOAddress is the interface to call the smart contract function
1489func (c *Client) WDelayerSetHermezGovernanceDAOAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
1490 c.rw.Lock()
1491 defer c.rw.Unlock()
1492 cpy := c.nextBlock().copy()
1493 defer func() { c.revertIfErr(err, cpy) }()
1494 if c.addr == nil {
1495 return nil, eth.ErrAccountNil
1496 }
1497
1498 log.Error("TODO")
1499 return nil, errTODO
1500}
1501
1502// WDelayerGetHermezKeeperAddress is the interface to call the smart contract function
1503func (c *Client) WDelayerGetHermezKeeperAddress() (*ethCommon.Address, error) {
1504 c.rw.RLock()
1505 defer c.rw.RUnlock()
1506
1507 log.Error("TODO")
1508 return nil, errTODO
1509}
1510
1511// WDelayerSetHermezKeeperAddress is the interface to call the smart contract function
1512func (c *Client) WDelayerSetHermezKeeperAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
1513 c.rw.Lock()
1514 defer c.rw.Unlock()
1515 cpy := c.nextBlock().copy()
1516 defer func() { c.revertIfErr(err, cpy) }()
1517 if c.addr == nil {
1518 return nil, eth.ErrAccountNil
1519 }
1520
1521 log.Error("TODO")
1522 return nil, errTODO
1523}
1524
1525// WDelayerGetWhiteHackGroupAddress is the interface to call the smart contract function
1526func (c *Client) WDelayerGetWhiteHackGroupAddress() (*ethCommon.Address, error) {
1527 c.rw.RLock()
1528 defer c.rw.RUnlock()
1529
1530 log.Error("TODO")
1531 return nil, errTODO
1532}
1533
1534// WDelayerSetWhiteHackGroupAddress is the interface to call the smart contract function
1535func (c *Client) WDelayerSetWhiteHackGroupAddress(newAddress ethCommon.Address) (tx *types.Transaction, err error) {
1536 c.rw.Lock()
1537 defer c.rw.Unlock()
1538 cpy := c.nextBlock().copy()
1539 defer func() { c.revertIfErr(err, cpy) }()
1540 if c.addr == nil {
1541 return nil, eth.ErrAccountNil
1542 }
1543
1544 log.Error("TODO")
1545 return nil, errTODO
1546}
1547
1548// WDelayerIsEmergencyMode is the interface to call the smart contract function
1549func (c *Client) WDelayerIsEmergencyMode() (bool, error) {
1550 c.rw.RLock()
1551 defer c.rw.RUnlock()
1552
1553 log.Error("TODO")
1554 return false, errTODO
1555}
1556
1557// WDelayerGetWithdrawalDelay is the interface to call the smart contract function
1558func (c *Client) WDelayerGetWithdrawalDelay() (*big.Int, error) {
1559 c.rw.RLock()
1560 defer c.rw.RUnlock()
1561
1562 log.Error("TODO")
1563 return nil, errTODO
1564}
1565
1566// WDelayerGetEmergencyModeStartingTime is the interface to call the smart contract function
1567func (c *Client) WDelayerGetEmergencyModeStartingTime() (*big.Int, error) {
1568 c.rw.RLock()
1569 defer c.rw.RUnlock()
1570
1571 log.Error("TODO")
1572 return nil, errTODO
1573}
1574
1575// WDelayerEnableEmergencyMode is the interface to call the smart contract function
1576func (c *Client) WDelayerEnableEmergencyMode() (tx *types.Transaction, err error) {
1577 c.rw.Lock()
1578 defer c.rw.Unlock()
1579 cpy := c.nextBlock().copy()
1580 defer func() { c.revertIfErr(err, cpy) }()
1581 if c.addr == nil {
1582 return nil, eth.ErrAccountNil
1583 }
1584
1585 log.Error("TODO")
1586 return nil, errTODO
1587}
1588
1589// WDelayerChangeWithdrawalDelay is the interface to call the smart contract function
1590func (c *Client) WDelayerChangeWithdrawalDelay(newWithdrawalDelay uint64) (tx *types.Transaction, err error) {
1591 c.rw.Lock()
1592 defer c.rw.Unlock()
1593 cpy := c.nextBlock().copy()
1594 defer func() { c.revertIfErr(err, cpy) }()
1595 if c.addr == nil {
1596 return nil, eth.ErrAccountNil
1597 }
1598
1599 nextBlock := c.nextBlock()
1600 w := nextBlock.WDelayer
1601 w.Vars.WithdrawalDelay = newWithdrawalDelay
1602 w.Events.NewWithdrawalDelay = append(w.Events.NewWithdrawalDelay,
1603 eth.WDelayerEventNewWithdrawalDelay{WithdrawalDelay: newWithdrawalDelay})
1604
1605 return w.addTransaction(newTransaction("changeWithdrawalDelay", newWithdrawalDelay)), nil
1606}
1607
1608// WDelayerDepositInfo is the interface to call the smart contract function
1609func (c *Client) WDelayerDepositInfo(owner, token ethCommon.Address) (eth.DepositState, error) {
1610 c.rw.RLock()
1611 defer c.rw.RUnlock()
1612
1613 log.Error("TODO")
1614 return eth.DepositState{}, errTODO
1615}
1616
1617// WDelayerDeposit is the interface to call the smart contract function
1618func (c *Client) WDelayerDeposit(onwer, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
1619 c.rw.Lock()
1620 defer c.rw.Unlock()
1621 cpy := c.nextBlock().copy()
1622 defer func() { c.revertIfErr(err, cpy) }()
1623 if c.addr == nil {
1624 return nil, eth.ErrAccountNil
1625 }
1626
1627 log.Error("TODO")
1628 return nil, errTODO
1629}
1630
1631// WDelayerWithdrawal is the interface to call the smart contract function
1632func (c *Client) WDelayerWithdrawal(owner, token ethCommon.Address) (tx *types.Transaction, err error) {
1633 c.rw.Lock()
1634 defer c.rw.Unlock()
1635 cpy := c.nextBlock().copy()
1636 defer func() { c.revertIfErr(err, cpy) }()
1637 if c.addr == nil {
1638 return nil, eth.ErrAccountNil
1639 }
1640
1641 log.Error("TODO")
1642 return nil, errTODO
1643}
1644
1645// WDelayerEscapeHatchWithdrawal is the interface to call the smart contract function
1646func (c *Client) WDelayerEscapeHatchWithdrawal(to, token ethCommon.Address, amount *big.Int) (tx *types.Transaction, err error) {
1647 c.rw.Lock()
1648 defer c.rw.Unlock()
1649 cpy := c.nextBlock().copy()
1650 defer func() { c.revertIfErr(err, cpy) }()
1651 if c.addr == nil {
1652 return nil, eth.ErrAccountNil
1653 }
1654
1655 log.Error("TODO")
1656 return nil, errTODO
1657}
1658
1659// WDelayerEventsByBlock returns the events in a block that happened in the WDelayer Contract
1660func (c *Client) WDelayerEventsByBlock(blockNum int64) (*eth.WDelayerEvents, *ethCommon.Hash, error) {
1661 c.rw.RLock()
1662 defer c.rw.RUnlock()
1663
1664 block, ok := c.blocks[blockNum]
1665 if !ok {
1666 return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum)
1667 }
1668 return &block.WDelayer.Events, &block.Eth.Hash, nil
1669}
1670
1671// WDelayerConstants returns the Constants of the WDelayer Contract
1672func (c *Client) WDelayerConstants() (*common.WDelayerConstants, error) {
1673 c.rw.RLock()
1674 defer c.rw.RUnlock()
1675
1676 return c.wDelayerConstants, nil
1677}