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 // TokenID = 0 is ETH. Set first entry in TokenList with 0x0 address for ETH.
336 TokenList: []ethCommon.Address{ethCommon.Address{}},
337 TokenMap: make(map[ethCommon.Address]bool),
338 MapL1TxQueue: mapL1TxQueue,
339 LastL1L2Batch: 0,
340 CurrentToForgeL1TxsNum: 0,
341 LastToForgeL1TxsNum: 1,
342 CurrentIdx: 0,
343 },
344 Vars: *setup.RollupVariables,
345 Txs: make(map[ethCommon.Hash]*types.Transaction),
346 Events: eth.NewRollupEvents(),
347 Constants: setup.RollupConstants,
348 },
349 Auction: &AuctionBlock{
350 State: eth.AuctionState{
351 Slots: make(map[int64]*eth.SlotState),
352 PendingBalances: make(map[ethCommon.Address]*big.Int),
353 Coordinators: make(map[ethCommon.Address]*eth.Coordinator),
354 },
355 Vars: *setup.AuctionVariables,
356 Txs: make(map[ethCommon.Hash]*types.Transaction),
357 Events: eth.NewAuctionEvents(),
358 Constants: setup.AuctionConstants,
359 },
360 Eth: &EthereumBlock{
361 BlockNum: blockNum,
362 Time: timer.Time(),
363 Hash: hasher.Next(),
364 ParentHash: ethCommon.Hash{},
365 Tokens: make(map[ethCommon.Address]eth.ERC20Consts),
366 },
367 }
368 blockCurrent.Rollup.Eth = blockCurrent.Eth
369 blockCurrent.Auction.Eth = blockCurrent.Eth
370 blocks[blockNum] = &blockCurrent
371 blockNext := blockCurrent.Next()
372 blocks[blockNum+1] = blockNext
373
374 return &Client{
375 rw: &sync.RWMutex{},
376 log: l,
377 addr: addr,
378 rollupConstants: setup.RollupConstants,
379 auctionConstants: setup.AuctionConstants,
380 blocks: blocks,
381 timer: timer,
382 hasher: hasher,
383 forgeBatchArgsPending: make(map[ethCommon.Hash]*eth.RollupForgeBatchArgs),
384 forgeBatchArgs: make(map[ethCommon.Hash]*eth.RollupForgeBatchArgs),
385 }
386}
387
388//
389// Mock Control
390//
391
392func (c *Client) setNextBlock(block *Block) {
393 c.blocks[c.blockNum+1] = block
394}
395
396func (c *Client) revertIfErr(err error, block *Block) {
397 if err != nil {
398 log.Infow("TestClient revert", "block", block.Eth.BlockNum, "err", err)
399 c.setNextBlock(block)
400 }
401}
402
403// Debugf calls log.Debugf if c.log is true
404func (c *Client) Debugf(template string, args ...interface{}) {
405 if c.log {
406 log.Debugf(template, args...)
407 }
408}
409
410// Debugw calls log.Debugw if c.log is true
411func (c *Client) Debugw(template string, kv ...interface{}) {
412 if c.log {
413 log.Debugw(template, kv...)
414 }
415}
416
417type hasher struct {
418 counter uint64
419}
420
421// Next returns the next hash
422func (h *hasher) Next() ethCommon.Hash {
423 var hash ethCommon.Hash
424 binary.LittleEndian.PutUint64(hash[:], h.counter)
425 h.counter++
426 return hash
427}
428
429func (c *Client) nextBlock() *Block {
430 return c.blocks[c.blockNum+1]
431}
432
433func (c *Client) currentBlock() *Block {
434 return c.blocks[c.blockNum]
435}
436
437// CtlSetAddr sets the address of the client
438func (c *Client) CtlSetAddr(addr ethCommon.Address) {
439 c.addr = &addr
440}
441
442// CtlMineBlock moves one block forward
443func (c *Client) CtlMineBlock() {
444 c.rw.Lock()
445 defer c.rw.Unlock()
446
447 blockCurrent := c.nextBlock()
448 c.blockNum++
449 c.maxBlockNum = c.blockNum
450 blockCurrent.Eth.Time = c.timer.Time()
451 blockCurrent.Eth.Hash = c.hasher.Next()
452 for ethTxHash, forgeBatchArgs := range c.forgeBatchArgsPending {
453 c.forgeBatchArgs[ethTxHash] = forgeBatchArgs
454 }
455 c.forgeBatchArgsPending = make(map[ethCommon.Hash]*eth.RollupForgeBatchArgs)
456
457 blockNext := blockCurrent.Next()
458 c.blocks[c.blockNum+1] = blockNext
459 c.Debugw("TestClient mined block", "blockNum", c.blockNum)
460}
461
462// CtlRollback discards the last mined block. Use this to replace a mined
463// block to simulate reorgs.
464func (c *Client) CtlRollback() {
465 c.rw.Lock()
466 defer c.rw.Unlock()
467
468 if c.blockNum == 0 {
469 panic("Can't rollback at blockNum = 0")
470 }
471 delete(c.blocks, c.blockNum+1) // delete next block
472 delete(c.blocks, c.blockNum) // delete current block
473 c.blockNum--
474 blockCurrent := c.blocks[c.blockNum]
475 blockNext := blockCurrent.Next()
476 c.blocks[c.blockNum+1] = blockNext
477}
478
479//
480// Ethereum
481//
482
483// EthCurrentBlock returns the current blockNum
484func (c *Client) EthCurrentBlock() (int64, error) {
485 c.rw.RLock()
486 defer c.rw.RUnlock()
487
488 if c.blockNum < c.maxBlockNum {
489 panic("blockNum has decreased. " +
490 "After a rollback you must mine to reach the same or higher blockNum")
491 }
492 return c.blockNum, nil
493}
494
495// EthTransactionReceipt returns the transaction receipt of the given txHash
496func (c *Client) EthTransactionReceipt(ctx context.Context, txHash ethCommon.Hash) (*types.Receipt, error) {
497 c.rw.RLock()
498 defer c.rw.RUnlock()
499
500 for i := int64(0); i < c.blockNum; i++ {
501 b := c.blocks[i]
502 _, ok := b.Rollup.Txs[txHash]
503 if !ok {
504 _, ok = b.Auction.Txs[txHash]
505 }
506 if ok {
507 return &types.Receipt{
508 TxHash: txHash,
509 Status: types.ReceiptStatusSuccessful,
510 BlockHash: b.Eth.Hash,
511 BlockNumber: big.NewInt(b.Eth.BlockNum),
512 }, nil
513 }
514 }
515
516 return nil, nil
517}
518
519// CtlAddERC20 adds an ERC20 token to the blockchain.
520func (c *Client) CtlAddERC20(tokenAddr ethCommon.Address, constants eth.ERC20Consts) {
521 nextBlock := c.nextBlock()
522 e := nextBlock.Eth
523 e.Tokens[tokenAddr] = constants
524}
525
526// EthERC20Consts returns the constants defined for a particular ERC20 Token instance.
527func (c *Client) EthERC20Consts(tokenAddr ethCommon.Address) (*eth.ERC20Consts, error) {
528 currentBlock := c.currentBlock()
529 e := currentBlock.Eth
530 if constants, ok := e.Tokens[tokenAddr]; ok {
531 return &constants, nil
532 }
533 return nil, fmt.Errorf("tokenAddr not found")
534}
535
536// func newHeader(number *big.Int) *types.Header {
537// return &types.Header{
538// Number: number,
539// Time: uint64(number.Int64()),
540// }
541// }
542
543// EthHeaderByNumber returns the *types.Header for the given block number in a
544// deterministic way.
545// func (c *Client) EthHeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
546// return newHeader(number), nil
547// }
548
549// EthBlockByNumber returns the *common.Block for the given block number in a
550// deterministic way.
551func (c *Client) EthBlockByNumber(ctx context.Context, blockNum int64) (*common.Block, error) {
552 c.rw.RLock()
553 defer c.rw.RUnlock()
554
555 block, ok := c.blocks[blockNum]
556 if !ok {
557 return nil, fmt.Errorf("block not found")
558 }
559 return &common.Block{
560 EthBlockNum: blockNum,
561 Timestamp: time.Unix(block.Eth.Time, 0),
562 Hash: block.Eth.Hash,
563 ParentHash: block.Eth.ParentHash,
564 }, nil
565}
566
567// EthAddress returns the ethereum address of the account loaded into the Client
568func (c *Client) EthAddress() (*ethCommon.Address, error) {
569 if c.addr == nil {
570 return nil, eth.ErrAccountNil
571 }
572 return c.addr, nil
573}
574
575var errTODO = fmt.Errorf("TODO: Not implemented yet")
576
577//
578// Rollup
579//
580
581// CtlAddL1TxUser adds an L1TxUser to the L1UserTxs queue of the Rollup
582func (c *Client) CtlAddL1TxUser(l1Tx *common.L1Tx) {
583 c.rw.Lock()
584 defer c.rw.Unlock()
585
586 nextBlock := c.nextBlock()
587 r := nextBlock.Rollup
588 queue := r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
589 if len(queue.L1TxQueue) >= eth.RollupConstMaxL1UserTx {
590 r.State.LastToForgeL1TxsNum++
591 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
592 queue = r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
593 }
594 if l1Tx.FromIdx != nil && int64(*l1Tx.FromIdx) > r.State.CurrentIdx {
595 panic("l1Tx.FromIdx > r.State.CurrentIdx")
596 }
597 if int(l1Tx.TokenID)+1 > len(r.State.TokenList) {
598 panic("l1Tx.TokenID + 1 > len(r.State.TokenList)")
599 }
600 queue.L1TxQueue = append(queue.L1TxQueue, *l1Tx)
601 r.Events.L1UserTx = append(r.Events.L1UserTx, eth.RollupEventL1UserTx{
602 L1Tx: *l1Tx,
603 ToForgeL1TxsNum: r.State.LastToForgeL1TxsNum,
604 Position: len(queue.L1TxQueue) - 1,
605 })
606}
607
608type transactionData struct {
609 Name string
610 Value interface{}
611}
612
613func newTransaction(name string, value interface{}) *types.Transaction {
614 data, err := json.Marshal(transactionData{name, value})
615 if err != nil {
616 panic(err)
617 }
618 return types.NewTransaction(0, ethCommon.Address{}, nil, 0, nil,
619 data)
620}
621
622// RollupForgeBatch is the interface to call the smart contract function
623func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs) (tx *types.Transaction, err error) {
624 c.rw.Lock()
625 defer c.rw.Unlock()
626 cpy := c.nextBlock().copy()
627 defer func() { c.revertIfErr(err, cpy) }()
628 if c.addr == nil {
629 return nil, eth.ErrAccountNil
630 }
631
632 a := c.nextBlock().Auction
633 ok, err := a.canForge(*c.addr, a.Eth.BlockNum)
634 if err != nil {
635 return nil, err
636 }
637 if !ok {
638 return nil, fmt.Errorf("incorrect slot")
639 }
640
641 // TODO: Verify proof
642
643 // Auction
644 err = a.forge(*c.addr)
645 if err != nil {
646 return nil, err
647 }
648
649 // TODO: If successful, store the tx in a successful array.
650 // TODO: If failed, store the tx in a failed array.
651 // TODO: Add method to move the tx to another block, reapply it there, and possibly go from successful to failed.
652
653 return c.addBatch(args)
654}
655
656// CtlAddBatch adds forged batch to the Rollup, without checking any ZKProof
657func (c *Client) CtlAddBatch(args *eth.RollupForgeBatchArgs) {
658 c.rw.Lock()
659 defer c.rw.Unlock()
660
661 if _, err := c.addBatch(args); err != nil {
662 panic(err)
663 }
664}
665
666func (c *Client) addBatch(args *eth.RollupForgeBatchArgs) (*types.Transaction, error) {
667 nextBlock := c.nextBlock()
668 r := nextBlock.Rollup
669 r.State.StateRoot = args.NewStRoot
670 if args.NewLastIdx < r.State.CurrentIdx {
671 return nil, fmt.Errorf("args.NewLastIdx < r.State.CurrentIdx")
672 }
673 r.State.CurrentIdx = args.NewLastIdx
674 r.State.ExitRoots = append(r.State.ExitRoots, args.NewExitRoot)
675 if args.L1Batch {
676 r.State.CurrentToForgeL1TxsNum++
677 if r.State.CurrentToForgeL1TxsNum == r.State.LastToForgeL1TxsNum {
678 r.State.LastToForgeL1TxsNum++
679 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
680 }
681 }
682 ethTx := r.addTransaction(newTransaction("forgebatch", args))
683 c.forgeBatchArgsPending[ethTx.Hash()] = args
684 r.Events.ForgeBatch = append(r.Events.ForgeBatch, eth.RollupEventForgeBatch{
685 BatchNum: int64(len(r.State.ExitRoots)),
686 EthTxHash: ethTx.Hash(),
687 })
688
689 return ethTx, nil
690}
691
692// RollupAddToken is the interface to call the smart contract function
693func (c *Client) RollupAddToken(tokenAddress ethCommon.Address) (tx *types.Transaction, err error) {
694 c.rw.Lock()
695 defer c.rw.Unlock()
696 cpy := c.nextBlock().copy()
697 defer func() { c.revertIfErr(err, cpy) }()
698 if c.addr == nil {
699 return nil, eth.ErrAccountNil
700 }
701
702 nextBlock := c.nextBlock()
703 r := nextBlock.Rollup
704 if _, ok := r.State.TokenMap[tokenAddress]; ok {
705 return nil, fmt.Errorf("Token %v already registered", tokenAddress)
706 }
707
708 r.State.TokenMap[tokenAddress] = true
709 r.State.TokenList = append(r.State.TokenList, tokenAddress)
710 r.Events.AddToken = append(r.Events.AddToken, eth.RollupEventAddToken{Address: tokenAddress,
711 TokenID: uint32(len(r.State.TokenList) - 1)})
712 return r.addTransaction(newTransaction("addtoken", tokenAddress)), nil
713}
714
715// RollupWithdrawSNARK is the interface to call the smart contract function
716// func (c *Client) RollupWithdrawSNARK() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol)
717// return nil, errTODO
718// }
719
720// RollupWithdraw is the interface to call the smart contract function
721func (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) {
722 c.rw.Lock()
723 defer c.rw.Unlock()
724 cpy := c.nextBlock().copy()
725 defer func() { c.revertIfErr(err, cpy) }()
726 if c.addr == nil {
727 return nil, eth.ErrAccountNil
728 }
729
730 log.Error("TODO")
731 return nil, errTODO
732}
733
734// RollupForceExit is the interface to call the smart contract function
735func (c *Client) RollupForceExit(fromIdx int64, amountF common.Float16, tokenID int64) (tx *types.Transaction, err error) {
736 c.rw.Lock()
737 defer c.rw.Unlock()
738 cpy := c.nextBlock().copy()
739 defer func() { c.revertIfErr(err, cpy) }()
740 if c.addr == nil {
741 return nil, eth.ErrAccountNil
742 }
743
744 log.Error("TODO")
745 return nil, errTODO
746}
747
748// RollupForceTransfer is the interface to call the smart contract function
749func (c *Client) RollupForceTransfer(fromIdx int64, amountF common.Float16, tokenID, toIdx int64) (tx *types.Transaction, err error) {
750 c.rw.Lock()
751 defer c.rw.Unlock()
752 cpy := c.nextBlock().copy()
753 defer func() { c.revertIfErr(err, cpy) }()
754 if c.addr == nil {
755 return nil, eth.ErrAccountNil
756 }
757
758 log.Error("TODO")
759 return nil, errTODO
760}
761
762// RollupCreateAccountDepositTransfer is the interface to call the smart contract function
763func (c *Client) RollupCreateAccountDepositTransfer(babyPubKey babyjub.PublicKey, loadAmountF, amountF common.Float16, tokenID int64, toIdx int64) (tx *types.Transaction, err error) {
764 c.rw.Lock()
765 defer c.rw.Unlock()
766 cpy := c.nextBlock().copy()
767 defer func() { c.revertIfErr(err, cpy) }()
768 if c.addr == nil {
769 return nil, eth.ErrAccountNil
770 }
771
772 log.Error("TODO")
773 return nil, errTODO
774}
775
776// RollupGetCurrentTokens is the interface to call the smart contract function
777func (c *Client) RollupGetCurrentTokens() (*big.Int, error) {
778 c.rw.RLock()
779 defer c.rw.RUnlock()
780
781 log.Error("TODO")
782 return nil, errTODO
783}
784
785// RollupDepositTransfer is the interface to call the smart contract function
786func (c *Client) RollupDepositTransfer(fromIdx int64, loadAmountF, amountF common.Float16, tokenID int64, toIdx int64) (tx *types.Transaction, err error) {
787 c.rw.Lock()
788 defer c.rw.Unlock()
789 cpy := c.nextBlock().copy()
790 defer func() { c.revertIfErr(err, cpy) }()
791 if c.addr == nil {
792 return nil, eth.ErrAccountNil
793 }
794
795 log.Error("TODO")
796 return nil, errTODO
797}
798
799// RollupDeposit is the interface to call the smart contract function
800func (c *Client) RollupDeposit(fromIdx int64, loadAmountF common.Float16, tokenID int64) (tx *types.Transaction, err error) {
801 c.rw.Lock()
802 defer c.rw.Unlock()
803 cpy := c.nextBlock().copy()
804 defer func() { c.revertIfErr(err, cpy) }()
805 if c.addr == nil {
806 return nil, eth.ErrAccountNil
807 }
808
809 log.Error("TODO")
810 return nil, errTODO
811}
812
813// RollupCreateAccountDepositFromRelayer is the interface to call the smart contract function
814func (c *Client) RollupCreateAccountDepositFromRelayer(accountCreationAuthSig []byte, babyPubKey babyjub.PublicKey, loadAmountF common.Float16) (tx *types.Transaction, err error) {
815 c.rw.Lock()
816 defer c.rw.Unlock()
817 cpy := c.nextBlock().copy()
818 defer func() { c.revertIfErr(err, cpy) }()
819 if c.addr == nil {
820 return nil, eth.ErrAccountNil
821 }
822
823 log.Error("TODO")
824 return nil, errTODO
825}
826
827// RollupCreateAccountDeposit is the interface to call the smart contract function
828func (c *Client) RollupCreateAccountDeposit(babyPubKey babyjub.PublicKey, loadAmountF common.Float16, tokenID int64) (tx *types.Transaction, err error) {
829 c.rw.Lock()
830 defer c.rw.Unlock()
831 cpy := c.nextBlock().copy()
832 defer func() { c.revertIfErr(err, cpy) }()
833 if c.addr == nil {
834 return nil, eth.ErrAccountNil
835 }
836
837 log.Error("TODO")
838 return nil, errTODO
839}
840
841// RollupGetTokenAddress is the interface to call the smart contract function
842// func (c *Client) RollupGetTokenAddress(tokenID int64) (*ethCommon.Address, error) {
843// c.rw.RLock()
844// defer c.rw.RUnlock()
845//
846// log.Error("TODO")
847// return nil, errTODO
848// }
849
850// RollupGetL1TxFromQueue is the interface to call the smart contract function
851// func (c *Client) RollupGetL1TxFromQueue(queue int64, position int64) ([]byte, error) {
852// c.rw.RLock()
853// defer c.rw.RUnlock()
854//
855// log.Error("TODO")
856// return nil, errTODO
857// }
858
859// RollupGetQueue is the interface to call the smart contract function
860// func (c *Client) RollupGetQueue(queue int64) ([]byte, error) {
861// c.rw.RLock()
862// defer c.rw.RUnlock()
863//
864// log.Error("TODO")
865// return nil, errTODO
866// }
867
868// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
869func (c *Client) RollupUpdateForgeL1L2BatchTimeout(newForgeL1Timeout int64) (tx *types.Transaction, err error) {
870 c.rw.Lock()
871 defer c.rw.Unlock()
872 cpy := c.nextBlock().copy()
873 defer func() { c.revertIfErr(err, cpy) }()
874 if c.addr == nil {
875 return nil, eth.ErrAccountNil
876 }
877
878 log.Error("TODO")
879 return nil, errTODO
880}
881
882// RollupUpdateFeeAddToken is the interface to call the smart contract function
883func (c *Client) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
884 c.rw.Lock()
885 defer c.rw.Unlock()
886 cpy := c.nextBlock().copy()
887 defer func() { c.revertIfErr(err, cpy) }()
888 if c.addr == nil {
889 return nil, eth.ErrAccountNil
890 }
891
892 log.Error("TODO")
893 return nil, errTODO
894}
895
896// RollupUpdateTokensHEZ is the interface to call the smart contract function
897// func (c *Client) RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (tx *types.Transaction, err error) {
898// c.rw.Lock()
899// defer c.rw.Unlock()
900// cpy := c.nextBlock().copy()
901// defer func() { c.revertIfErr(err, cpy) }()
902//
903// log.Error("TODO")
904// return nil, errTODO
905// }
906
907// RollupUpdateGovernance is the interface to call the smart contract function
908// func (c *Client) RollupUpdateGovernance() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol)
909// return nil, errTODO
910// }
911
912// RollupConstants returns the Constants of the Rollup Smart Contract
913func (c *Client) RollupConstants() (*eth.RollupPublicConstants, error) {
914 c.rw.RLock()
915 defer c.rw.RUnlock()
916
917 log.Error("TODO")
918 return nil, errTODO
919}
920
921// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
922func (c *Client) RollupEventsByBlock(blockNum int64) (*eth.RollupEvents, *ethCommon.Hash, error) {
923 c.rw.RLock()
924 defer c.rw.RUnlock()
925
926 block, ok := c.blocks[blockNum]
927 if !ok {
928 return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum)
929 }
930 return &block.Rollup.Events, &block.Eth.Hash, nil
931}
932
933// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the Rollup Smart Contract in the given transaction
934func (c *Client) RollupForgeBatchArgs(ethTxHash ethCommon.Hash) (*eth.RollupForgeBatchArgs, error) {
935 c.rw.RLock()
936 defer c.rw.RUnlock()
937
938 forgeBatchArgs, ok := c.forgeBatchArgs[ethTxHash]
939 if !ok {
940 return nil, fmt.Errorf("transaction not found")
941 }
942 return forgeBatchArgs, nil
943}
944
945//
946// Auction
947//
948
949// AuctionSetSlotDeadline is the interface to call the smart contract function
950func (c *Client) AuctionSetSlotDeadline(newDeadline uint8) (tx *types.Transaction, err error) {
951 c.rw.Lock()
952 defer c.rw.Unlock()
953 cpy := c.nextBlock().copy()
954 defer func() { c.revertIfErr(err, cpy) }()
955 if c.addr == nil {
956 return nil, eth.ErrAccountNil
957 }
958
959 log.Error("TODO")
960 return nil, errTODO
961}
962
963// AuctionGetSlotDeadline is the interface to call the smart contract function
964func (c *Client) AuctionGetSlotDeadline() (uint8, error) {
965 c.rw.RLock()
966 defer c.rw.RUnlock()
967
968 log.Error("TODO")
969 return 0, errTODO
970}
971
972// AuctionSetOpenAuctionSlots is the interface to call the smart contract function
973func (c *Client) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (tx *types.Transaction, err error) {
974 c.rw.Lock()
975 defer c.rw.Unlock()
976 cpy := c.nextBlock().copy()
977 defer func() { c.revertIfErr(err, cpy) }()
978 if c.addr == nil {
979 return nil, eth.ErrAccountNil
980 }
981
982 log.Error("TODO")
983 return nil, errTODO
984}
985
986// AuctionGetOpenAuctionSlots is the interface to call the smart contract function
987func (c *Client) AuctionGetOpenAuctionSlots() (uint16, error) {
988 c.rw.RLock()
989 defer c.rw.RUnlock()
990
991 log.Error("TODO")
992 return 0, errTODO
993}
994
995// AuctionSetClosedAuctionSlots is the interface to call the smart contract function
996func (c *Client) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (tx *types.Transaction, err error) {
997 c.rw.Lock()
998 defer c.rw.Unlock()
999 cpy := c.nextBlock().copy()
1000 defer func() { c.revertIfErr(err, cpy) }()
1001 if c.addr == nil {
1002 return nil, eth.ErrAccountNil
1003 }
1004
1005 log.Error("TODO")
1006 return nil, errTODO
1007}
1008
1009// AuctionGetClosedAuctionSlots is the interface to call the smart contract function
1010func (c *Client) AuctionGetClosedAuctionSlots() (uint16, error) {
1011 c.rw.RLock()
1012 defer c.rw.RUnlock()
1013
1014 log.Error("TODO")
1015 return 0, errTODO
1016}
1017
1018// AuctionSetOutbidding is the interface to call the smart contract function
1019func (c *Client) AuctionSetOutbidding(newOutbidding uint16) (tx *types.Transaction, err error) {
1020 c.rw.Lock()
1021 defer c.rw.Unlock()
1022 cpy := c.nextBlock().copy()
1023 defer func() { c.revertIfErr(err, cpy) }()
1024 if c.addr == nil {
1025 return nil, eth.ErrAccountNil
1026 }
1027
1028 log.Error("TODO")
1029 return nil, errTODO
1030}
1031
1032// AuctionGetOutbidding is the interface to call the smart contract function
1033func (c *Client) AuctionGetOutbidding() (uint16, error) {
1034 c.rw.RLock()
1035 defer c.rw.RUnlock()
1036
1037 log.Error("TODO")
1038 return 0, errTODO
1039}
1040
1041// AuctionSetAllocationRatio is the interface to call the smart contract function
1042func (c *Client) AuctionSetAllocationRatio(newAllocationRatio [3]uint16) (tx *types.Transaction, err error) {
1043 c.rw.Lock()
1044 defer c.rw.Unlock()
1045 cpy := c.nextBlock().copy()
1046 defer func() { c.revertIfErr(err, cpy) }()
1047 if c.addr == nil {
1048 return nil, eth.ErrAccountNil
1049 }
1050
1051 log.Error("TODO")
1052 return nil, errTODO
1053}
1054
1055// AuctionGetAllocationRatio is the interface to call the smart contract function
1056func (c *Client) AuctionGetAllocationRatio() ([3]uint16, error) {
1057 c.rw.RLock()
1058 defer c.rw.RUnlock()
1059
1060 log.Error("TODO")
1061 return [3]uint16{}, errTODO
1062}
1063
1064// AuctionSetDonationAddress is the interface to call the smart contract function
1065func (c *Client) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (tx *types.Transaction, err error) {
1066 c.rw.Lock()
1067 defer c.rw.Unlock()
1068 cpy := c.nextBlock().copy()
1069 defer func() { c.revertIfErr(err, cpy) }()
1070 if c.addr == nil {
1071 return nil, eth.ErrAccountNil
1072 }
1073
1074 log.Error("TODO")
1075 return nil, errTODO
1076}
1077
1078// AuctionGetDonationAddress is the interface to call the smart contract function
1079func (c *Client) AuctionGetDonationAddress() (*ethCommon.Address, error) {
1080 c.rw.RLock()
1081 defer c.rw.RUnlock()
1082
1083 log.Error("TODO")
1084 return nil, errTODO
1085}
1086
1087// AuctionSetBootCoordinator is the interface to call the smart contract function
1088func (c *Client) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address) (tx *types.Transaction, err error) {
1089 c.rw.Lock()
1090 defer c.rw.Unlock()
1091 cpy := c.nextBlock().copy()
1092 defer func() { c.revertIfErr(err, cpy) }()
1093 if c.addr == nil {
1094 return nil, eth.ErrAccountNil
1095 }
1096
1097 log.Error("TODO")
1098 return nil, errTODO
1099}
1100
1101// AuctionGetBootCoordinator is the interface to call the smart contract function
1102func (c *Client) AuctionGetBootCoordinator() (*ethCommon.Address, error) {
1103 c.rw.RLock()
1104 defer c.rw.RUnlock()
1105
1106 currentBlock := c.currentBlock()
1107 a := currentBlock.Auction
1108
1109 return &a.Vars.BootCoordinator, nil
1110}
1111
1112// AuctionChangeDefaultSlotSetBid is the interface to call the smart contract function
1113func (c *Client) AuctionChangeDefaultSlotSetBid(slotSet int64, newInitialMinBid *big.Int) (tx *types.Transaction, err error) {
1114 c.rw.Lock()
1115 defer c.rw.Unlock()
1116 cpy := c.nextBlock().copy()
1117 defer func() { c.revertIfErr(err, cpy) }()
1118 if c.addr == nil {
1119 return nil, eth.ErrAccountNil
1120 }
1121
1122 log.Error("TODO")
1123 return nil, errTODO
1124}
1125
1126// AuctionSetCoordinator is the interface to call the smart contract function
1127func (c *Client) AuctionSetCoordinator(forger ethCommon.Address, URL string) (tx *types.Transaction, err error) {
1128 c.rw.Lock()
1129 defer c.rw.Unlock()
1130 cpy := c.nextBlock().copy()
1131 defer func() { c.revertIfErr(err, cpy) }()
1132 if c.addr == nil {
1133 return nil, eth.ErrAccountNil
1134 }
1135
1136 nextBlock := c.nextBlock()
1137 a := nextBlock.Auction
1138
1139 a.State.Coordinators[*c.addr] = ð.Coordinator{
1140 Forger: forger,
1141 URL: URL,
1142 }
1143
1144 a.Events.SetCoordinator = append(a.Events.SetCoordinator,
1145 eth.AuctionEventSetCoordinator{
1146 BidderAddress: *c.addr,
1147 ForgerAddress: forger,
1148 CoordinatorURL: URL,
1149 })
1150
1151 type data struct {
1152 BidderAddress ethCommon.Address
1153 ForgerAddress ethCommon.Address
1154 URL string
1155 }
1156 return a.addTransaction(newTransaction("registercoordinator", data{*c.addr, forger, URL})), nil
1157}
1158
1159// AuctionIsRegisteredCoordinator is the interface to call the smart contract function
1160func (c *Client) AuctionIsRegisteredCoordinator(forgerAddress ethCommon.Address) (bool, error) {
1161 c.rw.RLock()
1162 defer c.rw.RUnlock()
1163
1164 log.Error("TODO")
1165 return false, errTODO
1166}
1167
1168// AuctionUpdateCoordinatorInfo is the interface to call the smart contract function
1169func (c *Client) AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (tx *types.Transaction, err error) {
1170 c.rw.Lock()
1171 defer c.rw.Unlock()
1172 cpy := c.nextBlock().copy()
1173 defer func() { c.revertIfErr(err, cpy) }()
1174 if c.addr == nil {
1175 return nil, eth.ErrAccountNil
1176 }
1177
1178 log.Error("TODO")
1179 return nil, errTODO
1180}
1181
1182// AuctionGetSlotNumber is the interface to call the smart contract function
1183func (c *Client) AuctionGetSlotNumber(blockNum int64) (int64, error) {
1184 c.rw.RLock()
1185 defer c.rw.RUnlock()
1186
1187 currentBlock := c.currentBlock()
1188 a := currentBlock.Auction
1189 return a.getSlotNumber(blockNum), nil
1190}
1191
1192// AuctionGetCurrentSlotNumber is the interface to call the smart contract function
1193func (c *Client) AuctionGetCurrentSlotNumber() (int64, error) {
1194 c.rw.RLock()
1195 defer c.rw.RUnlock()
1196
1197 log.Error("TODO")
1198 return 0, errTODO
1199}
1200
1201// AuctionGetMinBidBySlot is the interface to call the smart contract function
1202func (c *Client) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) {
1203 c.rw.RLock()
1204 defer c.rw.RUnlock()
1205
1206 log.Error("TODO")
1207 return nil, errTODO
1208}
1209
1210// AuctionGetDefaultSlotSetBid is the interface to call the smart contract function
1211func (c *Client) AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, error) {
1212 c.rw.RLock()
1213 defer c.rw.RUnlock()
1214
1215 log.Error("TODO")
1216 return nil, errTODO
1217}
1218
1219// AuctionGetSlotSet is the interface to call the smart contract function
1220func (c *Client) AuctionGetSlotSet(slot int64) (*big.Int, error) {
1221 c.rw.RLock()
1222 defer c.rw.RUnlock()
1223
1224 log.Error("TODO")
1225 return nil, errTODO
1226}
1227
1228// AuctionTokensReceived is the interface to call the smart contract function
1229// func (c *Client) AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, userData, operatorData []byte) error {
1230// return errTODO
1231// }
1232
1233// AuctionBid is the interface to call the smart contract function
1234func (c *Client) AuctionBid(slot int64, bidAmount *big.Int) (tx *types.Transaction, err error) {
1235 c.rw.Lock()
1236 defer c.rw.Unlock()
1237 cpy := c.nextBlock().copy()
1238 defer func() { func() { c.revertIfErr(err, cpy) }() }()
1239 if c.addr == nil {
1240 return nil, eth.ErrAccountNil
1241 }
1242
1243 nextBlock := c.nextBlock()
1244 a := nextBlock.Auction
1245
1246 if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
1247 return nil, errBidClosed
1248 }
1249
1250 if slot >= a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots)+int64(a.Vars.OpenAuctionSlots) {
1251 return nil, errBidNotOpen
1252 }
1253
1254 minBid, err := a.getMinBidBySlot(slot)
1255 if err != nil {
1256 return nil, err
1257 }
1258 if bidAmount.Cmp(minBid) == -1 {
1259 return nil, errBidBelowMin
1260 }
1261
1262 if _, ok := a.State.Coordinators[*c.addr]; !ok {
1263 return nil, errCoordNotReg
1264 }
1265
1266 slotState, ok := a.State.Slots[slot]
1267 if !ok {
1268 slotState = eth.NewSlotState()
1269 a.State.Slots[slot] = slotState
1270 }
1271 slotState.Bidder = *c.addr
1272 slotState.BidAmount = bidAmount
1273
1274 a.Events.NewBid = append(a.Events.NewBid,
1275 eth.AuctionEventNewBid{Slot: slot, BidAmount: bidAmount, Bidder: *c.addr})
1276
1277 type data struct {
1278 Slot int64
1279 BidAmount *big.Int
1280 Bidder ethCommon.Address
1281 }
1282 return a.addTransaction(newTransaction("bid", data{slot, bidAmount, *c.addr})), nil
1283}
1284
1285// AuctionMultiBid is the interface to call the smart contract function
1286func (c *Client) AuctionMultiBid(startingSlot int64, endingSlot int64, slotSet [6]bool, maxBid, closedMinBid, budget *big.Int) (tx *types.Transaction, err error) {
1287 c.rw.Lock()
1288 defer c.rw.Unlock()
1289 cpy := c.nextBlock().copy()
1290 defer func() { c.revertIfErr(err, cpy) }()
1291 if c.addr == nil {
1292 return nil, eth.ErrAccountNil
1293 }
1294
1295 log.Error("TODO")
1296 return nil, errTODO
1297}
1298
1299// AuctionCanForge is the interface to call the smart contract function
1300func (c *Client) AuctionCanForge(forger ethCommon.Address, blockNum int64) (bool, error) {
1301 c.rw.RLock()
1302 defer c.rw.RUnlock()
1303
1304 currentBlock := c.currentBlock()
1305 a := currentBlock.Auction
1306 return a.canForge(forger, blockNum)
1307}
1308
1309// AuctionForge is the interface to call the smart contract function
1310func (c *Client) AuctionForge(forger ethCommon.Address) (tx *types.Transaction, err error) {
1311 c.rw.Lock()
1312 defer c.rw.Unlock()
1313 cpy := c.nextBlock().copy()
1314 defer func() { c.revertIfErr(err, cpy) }()
1315 if c.addr == nil {
1316 return nil, eth.ErrAccountNil
1317 }
1318
1319 log.Error("TODO")
1320 return nil, errTODO
1321}
1322
1323// AuctionClaimHEZ is the interface to call the smart contract function
1324func (c *Client) AuctionClaimHEZ() (tx *types.Transaction, err error) {
1325 c.rw.Lock()
1326 defer c.rw.Unlock()
1327 cpy := c.nextBlock().copy()
1328 defer func() { c.revertIfErr(err, cpy) }()
1329 if c.addr == nil {
1330 return nil, eth.ErrAccountNil
1331 }
1332
1333 log.Error("TODO")
1334 return nil, errTODO
1335}
1336
1337// AuctionGetClaimableHEZ is the interface to call the smart contract function
1338func (c *Client) AuctionGetClaimableHEZ(bidder ethCommon.Address) (*big.Int, error) {
1339 c.rw.RLock()
1340 defer c.rw.RUnlock()
1341
1342 log.Error("TODO")
1343 return nil, errTODO
1344}
1345
1346// AuctionConstants returns the Constants of the Auction Smart Contract
1347func (c *Client) AuctionConstants() (*eth.AuctionConstants, error) {
1348 c.rw.RLock()
1349 defer c.rw.RUnlock()
1350
1351 return c.auctionConstants, nil
1352}
1353
1354// AuctionEventsByBlock returns the events in a block that happened in the Auction Smart Contract
1355func (c *Client) AuctionEventsByBlock(blockNum int64) (*eth.AuctionEvents, *ethCommon.Hash, error) {
1356 c.rw.RLock()
1357 defer c.rw.RUnlock()
1358
1359 block, ok := c.blocks[blockNum]
1360 if !ok {
1361 return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum)
1362 }
1363 return &block.Auction.Events, &block.Eth.Hash, nil
1364}