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