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