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