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