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// RollupL1UserTxERC20Permit is the interface to call the smart contract function
625func (c *Client) RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error) {
626 log.Error("TODO")
627 return nil, errTODO
628}
629
630// RollupL1UserTxERC20ETH sends an L1UserTx to the Rollup.
631func (c *Client) RollupL1UserTxERC20ETH(
632 fromBJJ *babyjub.PublicKey,
633 fromIdx int64,
634 loadAmount *big.Int,
635 amount *big.Int,
636 tokenID uint32,
637 toIdx int64,
638) (tx *types.Transaction, err error) {
639 c.rw.Lock()
640 defer c.rw.Unlock()
641 cpy := c.nextBlock().copy()
642 defer func() { c.revertIfErr(err, cpy) }()
643
644 _, err = common.NewFloat16(amount)
645 if err != nil {
646 return nil, err
647 }
648 _, err = common.NewFloat16(loadAmount)
649 if err != nil {
650 return nil, err
651 }
652
653 nextBlock := c.nextBlock()
654 r := nextBlock.Rollup
655 queue := r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
656 if len(queue.L1TxQueue) >= eth.RollupConstMaxL1UserTx {
657 r.State.LastToForgeL1TxsNum++
658 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
659 queue = r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum]
660 }
661 if fromIdx > r.State.CurrentIdx {
662 panic("l1Tx.FromIdx > r.State.CurrentIdx")
663 }
664 if int(tokenID)+1 > len(r.State.TokenList) {
665 panic("l1Tx.TokenID + 1 > len(r.State.TokenList)")
666 }
667 toForgeL1TxsNum := r.State.LastToForgeL1TxsNum
668 l1Tx, err := common.NewL1Tx(&common.L1Tx{
669 FromIdx: common.Idx(fromIdx),
670 FromEthAddr: *c.addr,
671 FromBJJ: fromBJJ,
672 Amount: amount,
673 LoadAmount: loadAmount,
674 TokenID: common.TokenID(tokenID),
675 ToIdx: common.Idx(toIdx),
676 ToForgeL1TxsNum: &toForgeL1TxsNum,
677 Position: len(queue.L1TxQueue) - 1,
678 UserOrigin: true,
679 })
680 if err != nil {
681 return nil, err
682 }
683
684 queue.L1TxQueue = append(queue.L1TxQueue, *l1Tx)
685 r.Events.L1UserTx = append(r.Events.L1UserTx, eth.RollupEventL1UserTx{
686 L1UserTx: *l1Tx,
687 })
688 return r.addTransaction(newTransaction("l1UserTxERC20ETH", l1Tx)), nil
689}
690
691// RollupL1UserTxERC777 is the interface to call the smart contract function
692// func (c *Client) RollupL1UserTxERC777(fromBJJ *babyjub.PublicKey, fromIdx int64, loadAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error) {
693// log.Error("TODO")
694// return nil, errTODO
695// }
696
697// RollupRegisterTokensCount is the interface to call the smart contract function
698func (c *Client) RollupRegisterTokensCount() (*big.Int, error) {
699 log.Error("TODO")
700 return nil, errTODO
701}
702
703// RollupWithdrawCircuit is the interface to call the smart contract function
704func (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) {
705 log.Error("TODO")
706 return nil, errTODO
707}
708
709// RollupWithdrawMerkleProof is the interface to call the smart contract function
710func (c *Client) RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error) {
711 log.Error("TODO")
712 return nil, errTODO
713}
714
715type transactionData struct {
716 Name string
717 Value interface{}
718}
719
720func newTransaction(name string, value interface{}) *types.Transaction {
721 data, err := json.Marshal(transactionData{name, value})
722 if err != nil {
723 panic(err)
724 }
725 return types.NewTransaction(0, ethCommon.Address{}, nil, 0, nil,
726 data)
727}
728
729// RollupForgeBatch is the interface to call the smart contract function
730func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs) (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 a := c.nextBlock().Auction
740 ok, err := a.canForge(*c.addr, a.Eth.BlockNum)
741 if err != nil {
742 return nil, err
743 }
744 if !ok {
745 return nil, fmt.Errorf("incorrect slot")
746 }
747
748 // TODO: Verify proof
749
750 // Auction
751 err = a.forge(*c.addr)
752 if err != nil {
753 return nil, err
754 }
755
756 // TODO: If successful, store the tx in a successful array.
757 // TODO: If failed, store the tx in a failed array.
758 // TODO: Add method to move the tx to another block, reapply it there, and possibly go from successful to failed.
759
760 return c.addBatch(args)
761}
762
763// CtlAddBatch adds forged batch to the Rollup, without checking any ZKProof
764func (c *Client) CtlAddBatch(args *eth.RollupForgeBatchArgs) {
765 c.rw.Lock()
766 defer c.rw.Unlock()
767
768 if _, err := c.addBatch(args); err != nil {
769 panic(err)
770 }
771}
772
773func (c *Client) addBatch(args *eth.RollupForgeBatchArgs) (*types.Transaction, error) {
774 nextBlock := c.nextBlock()
775 r := nextBlock.Rollup
776 r.State.StateRoot = args.NewStRoot
777 if args.NewLastIdx < r.State.CurrentIdx {
778 return nil, fmt.Errorf("args.NewLastIdx < r.State.CurrentIdx")
779 }
780 r.State.CurrentIdx = args.NewLastIdx
781 r.State.ExitRoots = append(r.State.ExitRoots, args.NewExitRoot)
782 if args.L1Batch {
783 r.State.CurrentToForgeL1TxsNum++
784 if r.State.CurrentToForgeL1TxsNum == r.State.LastToForgeL1TxsNum {
785 r.State.LastToForgeL1TxsNum++
786 r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct()
787 }
788 }
789 ethTx := r.addTransaction(newTransaction("forgebatch", args))
790 c.forgeBatchArgsPending[ethTx.Hash()] = &batch{*args, *c.addr}
791 r.Events.ForgeBatch = append(r.Events.ForgeBatch, eth.RollupEventForgeBatch{
792 BatchNum: int64(len(r.State.ExitRoots)),
793 EthTxHash: ethTx.Hash(),
794 })
795
796 return ethTx, nil
797}
798
799// RollupAddTokenSimple is a wrapper around RollupAddToken that automatically
800// sets `deadlie`.
801func (c *Client) RollupAddTokenSimple(tokenAddress ethCommon.Address, feeAddToken *big.Int) (tx *types.Transaction, err error) {
802 return c.RollupAddToken(tokenAddress, feeAddToken, big.NewInt(9999)) //nolint:gomnd
803}
804
805// RollupAddToken is the interface to call the smart contract function
806func (c *Client) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken *big.Int,
807 deadline *big.Int) (tx *types.Transaction, err error) {
808 c.rw.Lock()
809 defer c.rw.Unlock()
810 cpy := c.nextBlock().copy()
811 defer func() { c.revertIfErr(err, cpy) }()
812 if c.addr == nil {
813 return nil, eth.ErrAccountNil
814 }
815
816 nextBlock := c.nextBlock()
817 r := nextBlock.Rollup
818 if _, ok := r.State.TokenMap[tokenAddress]; ok {
819 return nil, fmt.Errorf("Token %v already registered", tokenAddress)
820 }
821 if feeAddToken.Cmp(r.Vars.FeeAddToken) != 0 {
822 return nil, fmt.Errorf("Expected fee: %v but got: %v", r.Vars.FeeAddToken, feeAddToken)
823 }
824
825 r.State.TokenMap[tokenAddress] = true
826 r.State.TokenList = append(r.State.TokenList, tokenAddress)
827 r.Events.AddToken = append(r.Events.AddToken, eth.RollupEventAddToken{TokenAddress: tokenAddress,
828 TokenID: uint32(len(r.State.TokenList) - 1)})
829 return r.addTransaction(newTransaction("addtoken", tokenAddress)), nil
830}
831
832// RollupGetCurrentTokens is the interface to call the smart contract function
833func (c *Client) RollupGetCurrentTokens() (*big.Int, error) {
834 c.rw.RLock()
835 defer c.rw.RUnlock()
836
837 log.Error("TODO")
838 return nil, errTODO
839}
840
841// RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
842func (c *Client) RollupUpdateForgeL1L2BatchTimeout(newForgeL1Timeout int64) (tx *types.Transaction, err error) {
843 c.rw.Lock()
844 defer c.rw.Unlock()
845 cpy := c.nextBlock().copy()
846 defer func() { c.revertIfErr(err, cpy) }()
847 if c.addr == nil {
848 return nil, eth.ErrAccountNil
849 }
850
851 log.Error("TODO")
852 return nil, errTODO
853}
854
855// RollupUpdateFeeAddToken is the interface to call the smart contract function
856func (c *Client) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
857 c.rw.Lock()
858 defer c.rw.Unlock()
859 cpy := c.nextBlock().copy()
860 defer func() { c.revertIfErr(err, cpy) }()
861 if c.addr == nil {
862 return nil, eth.ErrAccountNil
863 }
864
865 log.Error("TODO")
866 return nil, errTODO
867}
868
869// RollupUpdateTokensHEZ is the interface to call the smart contract function
870// func (c *Client) RollupUpdateTokensHEZ(newTokenHEZ ethCommon.Address) (tx *types.Transaction, err error) {
871// c.rw.Lock()
872// defer c.rw.Unlock()
873// cpy := c.nextBlock().copy()
874// defer func() { c.revertIfErr(err, cpy) }()
875//
876// log.Error("TODO")
877// return nil, errTODO
878// }
879
880// RollupUpdateGovernance is the interface to call the smart contract function
881// func (c *Client) RollupUpdateGovernance() (*types.Transaction, error) { // TODO (Not defined in Hermez.sol)
882// return nil, errTODO
883// }
884
885// RollupConstants returns the Constants of the Rollup Smart Contract
886func (c *Client) RollupConstants() (*eth.RollupPublicConstants, error) {
887 c.rw.RLock()
888 defer c.rw.RUnlock()
889
890 log.Error("TODO")
891 return nil, errTODO
892}
893
894// RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
895func (c *Client) RollupEventsByBlock(blockNum int64) (*eth.RollupEvents, *ethCommon.Hash, error) {
896 c.rw.RLock()
897 defer c.rw.RUnlock()
898
899 block, ok := c.blocks[blockNum]
900 if !ok {
901 return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum)
902 }
903 return &block.Rollup.Events, &block.Eth.Hash, nil
904}
905
906// RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the Rollup Smart Contract in the given transaction
907func (c *Client) RollupForgeBatchArgs(ethTxHash ethCommon.Hash) (*eth.RollupForgeBatchArgs, *ethCommon.Address, error) {
908 c.rw.RLock()
909 defer c.rw.RUnlock()
910
911 batch, ok := c.forgeBatchArgs[ethTxHash]
912 if !ok {
913 return nil, nil, fmt.Errorf("transaction not found")
914 }
915 return &batch.ForgeBatchArgs, &batch.Sender, nil
916}
917
918//
919// Auction
920//
921
922// AuctionSetSlotDeadline is the interface to call the smart contract function
923func (c *Client) AuctionSetSlotDeadline(newDeadline uint8) (tx *types.Transaction, err error) {
924 c.rw.Lock()
925 defer c.rw.Unlock()
926 cpy := c.nextBlock().copy()
927 defer func() { c.revertIfErr(err, cpy) }()
928 if c.addr == nil {
929 return nil, eth.ErrAccountNil
930 }
931
932 log.Error("TODO")
933 return nil, errTODO
934}
935
936// AuctionGetSlotDeadline is the interface to call the smart contract function
937func (c *Client) AuctionGetSlotDeadline() (uint8, error) {
938 c.rw.RLock()
939 defer c.rw.RUnlock()
940
941 log.Error("TODO")
942 return 0, errTODO
943}
944
945// AuctionSetOpenAuctionSlots is the interface to call the smart contract function
946func (c *Client) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (tx *types.Transaction, err error) {
947 c.rw.Lock()
948 defer c.rw.Unlock()
949 cpy := c.nextBlock().copy()
950 defer func() { c.revertIfErr(err, cpy) }()
951 if c.addr == nil {
952 return nil, eth.ErrAccountNil
953 }
954
955 log.Error("TODO")
956 return nil, errTODO
957}
958
959// AuctionGetOpenAuctionSlots is the interface to call the smart contract function
960func (c *Client) AuctionGetOpenAuctionSlots() (uint16, error) {
961 c.rw.RLock()
962 defer c.rw.RUnlock()
963
964 log.Error("TODO")
965 return 0, errTODO
966}
967
968// AuctionSetClosedAuctionSlots is the interface to call the smart contract function
969func (c *Client) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (tx *types.Transaction, err error) {
970 c.rw.Lock()
971 defer c.rw.Unlock()
972 cpy := c.nextBlock().copy()
973 defer func() { c.revertIfErr(err, cpy) }()
974 if c.addr == nil {
975 return nil, eth.ErrAccountNil
976 }
977
978 log.Error("TODO")
979 return nil, errTODO
980}
981
982// AuctionGetClosedAuctionSlots is the interface to call the smart contract function
983func (c *Client) AuctionGetClosedAuctionSlots() (uint16, error) {
984 c.rw.RLock()
985 defer c.rw.RUnlock()
986
987 log.Error("TODO")
988 return 0, errTODO
989}
990
991// AuctionSetOutbidding is the interface to call the smart contract function
992func (c *Client) AuctionSetOutbidding(newOutbidding uint16) (tx *types.Transaction, err error) {
993 c.rw.Lock()
994 defer c.rw.Unlock()
995 cpy := c.nextBlock().copy()
996 defer func() { c.revertIfErr(err, cpy) }()
997 if c.addr == nil {
998 return nil, eth.ErrAccountNil
999 }
1000
1001 log.Error("TODO")
1002 return nil, errTODO
1003}
1004
1005// AuctionGetOutbidding is the interface to call the smart contract function
1006func (c *Client) AuctionGetOutbidding() (uint16, error) {
1007 c.rw.RLock()
1008 defer c.rw.RUnlock()
1009
1010 log.Error("TODO")
1011 return 0, errTODO
1012}
1013
1014// AuctionSetAllocationRatio is the interface to call the smart contract function
1015func (c *Client) AuctionSetAllocationRatio(newAllocationRatio [3]uint16) (tx *types.Transaction, err error) {
1016 c.rw.Lock()
1017 defer c.rw.Unlock()
1018 cpy := c.nextBlock().copy()
1019 defer func() { c.revertIfErr(err, cpy) }()
1020 if c.addr == nil {
1021 return nil, eth.ErrAccountNil
1022 }
1023
1024 log.Error("TODO")
1025 return nil, errTODO
1026}
1027
1028// AuctionGetAllocationRatio is the interface to call the smart contract function
1029func (c *Client) AuctionGetAllocationRatio() ([3]uint16, error) {
1030 c.rw.RLock()
1031 defer c.rw.RUnlock()
1032
1033 log.Error("TODO")
1034 return [3]uint16{}, errTODO
1035}
1036
1037// AuctionSetDonationAddress is the interface to call the smart contract function
1038func (c *Client) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (tx *types.Transaction, err error) {
1039 c.rw.Lock()
1040 defer c.rw.Unlock()
1041 cpy := c.nextBlock().copy()
1042 defer func() { c.revertIfErr(err, cpy) }()
1043 if c.addr == nil {
1044 return nil, eth.ErrAccountNil
1045 }
1046
1047 log.Error("TODO")
1048 return nil, errTODO
1049}
1050
1051// AuctionGetDonationAddress is the interface to call the smart contract function
1052func (c *Client) AuctionGetDonationAddress() (*ethCommon.Address, error) {
1053 c.rw.RLock()
1054 defer c.rw.RUnlock()
1055
1056 log.Error("TODO")
1057 return nil, errTODO
1058}
1059
1060// AuctionSetBootCoordinator is the interface to call the smart contract function
1061func (c *Client) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address) (tx *types.Transaction, err error) {
1062 c.rw.Lock()
1063 defer c.rw.Unlock()
1064 cpy := c.nextBlock().copy()
1065 defer func() { c.revertIfErr(err, cpy) }()
1066 if c.addr == nil {
1067 return nil, eth.ErrAccountNil
1068 }
1069
1070 log.Error("TODO")
1071 return nil, errTODO
1072}
1073
1074// AuctionGetBootCoordinator is the interface to call the smart contract function
1075func (c *Client) AuctionGetBootCoordinator() (*ethCommon.Address, error) {
1076 c.rw.RLock()
1077 defer c.rw.RUnlock()
1078
1079 currentBlock := c.currentBlock()
1080 a := currentBlock.Auction
1081
1082 return &a.Vars.BootCoordinator, nil
1083}
1084
1085// AuctionChangeDefaultSlotSetBid is the interface to call the smart contract function
1086func (c *Client) AuctionChangeDefaultSlotSetBid(slotSet int64, newInitialMinBid *big.Int) (tx *types.Transaction, err error) {
1087 c.rw.Lock()
1088 defer c.rw.Unlock()
1089 cpy := c.nextBlock().copy()
1090 defer func() { c.revertIfErr(err, cpy) }()
1091 if c.addr == nil {
1092 return nil, eth.ErrAccountNil
1093 }
1094
1095 log.Error("TODO")
1096 return nil, errTODO
1097}
1098
1099// AuctionSetCoordinator is the interface to call the smart contract function
1100func (c *Client) AuctionSetCoordinator(forger ethCommon.Address, URL string) (tx *types.Transaction, err error) {
1101 c.rw.Lock()
1102 defer c.rw.Unlock()
1103 cpy := c.nextBlock().copy()
1104 defer func() { c.revertIfErr(err, cpy) }()
1105 if c.addr == nil {
1106 return nil, eth.ErrAccountNil
1107 }
1108
1109 nextBlock := c.nextBlock()
1110 a := nextBlock.Auction
1111
1112 a.State.Coordinators[*c.addr] = ð.Coordinator{
1113 Forger: forger,
1114 URL: URL,
1115 }
1116
1117 a.Events.SetCoordinator = append(a.Events.SetCoordinator,
1118 eth.AuctionEventSetCoordinator{
1119 BidderAddress: *c.addr,
1120 ForgerAddress: forger,
1121 CoordinatorURL: URL,
1122 })
1123
1124 type data struct {
1125 BidderAddress ethCommon.Address
1126 ForgerAddress ethCommon.Address
1127 URL string
1128 }
1129 return a.addTransaction(newTransaction("registercoordinator", data{*c.addr, forger, URL})), nil
1130}
1131
1132// AuctionIsRegisteredCoordinator is the interface to call the smart contract function
1133func (c *Client) AuctionIsRegisteredCoordinator(forgerAddress ethCommon.Address) (bool, error) {
1134 c.rw.RLock()
1135 defer c.rw.RUnlock()
1136
1137 log.Error("TODO")
1138 return false, errTODO
1139}
1140
1141// AuctionUpdateCoordinatorInfo is the interface to call the smart contract function
1142func (c *Client) AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (tx *types.Transaction, err error) {
1143 c.rw.Lock()
1144 defer c.rw.Unlock()
1145 cpy := c.nextBlock().copy()
1146 defer func() { c.revertIfErr(err, cpy) }()
1147 if c.addr == nil {
1148 return nil, eth.ErrAccountNil
1149 }
1150
1151 log.Error("TODO")
1152 return nil, errTODO
1153}
1154
1155// AuctionGetSlotNumber is the interface to call the smart contract function
1156func (c *Client) AuctionGetSlotNumber(blockNum int64) (int64, error) {
1157 c.rw.RLock()
1158 defer c.rw.RUnlock()
1159
1160 currentBlock := c.currentBlock()
1161 a := currentBlock.Auction
1162 return a.getSlotNumber(blockNum), nil
1163}
1164
1165// AuctionGetCurrentSlotNumber is the interface to call the smart contract function
1166func (c *Client) AuctionGetCurrentSlotNumber() (int64, error) {
1167 c.rw.RLock()
1168 defer c.rw.RUnlock()
1169
1170 log.Error("TODO")
1171 return 0, errTODO
1172}
1173
1174// AuctionGetMinBidBySlot is the interface to call the smart contract function
1175func (c *Client) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) {
1176 c.rw.RLock()
1177 defer c.rw.RUnlock()
1178
1179 log.Error("TODO")
1180 return nil, errTODO
1181}
1182
1183// AuctionGetDefaultSlotSetBid is the interface to call the smart contract function
1184func (c *Client) AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, error) {
1185 c.rw.RLock()
1186 defer c.rw.RUnlock()
1187
1188 log.Error("TODO")
1189 return nil, errTODO
1190}
1191
1192// AuctionGetSlotSet is the interface to call the smart contract function
1193func (c *Client) AuctionGetSlotSet(slot int64) (*big.Int, error) {
1194 c.rw.RLock()
1195 defer c.rw.RUnlock()
1196
1197 log.Error("TODO")
1198 return nil, errTODO
1199}
1200
1201// AuctionTokensReceived is the interface to call the smart contract function
1202// func (c *Client) AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, userData, operatorData []byte) error {
1203// return errTODO
1204// }
1205
1206// AuctionBidSimple is a wrapper around AuctionBid that automatically sets `amount` and `deadline`.
1207func (c *Client) AuctionBidSimple(slot int64, bidAmount *big.Int) (tx *types.Transaction, err error) {
1208 return c.AuctionBid(bidAmount, slot, bidAmount, big.NewInt(99999)) //nolint:gomnd
1209}
1210
1211// AuctionBid is the interface to call the smart contract function. This
1212// implementation behaves as if any address has infinite tokens.
1213func (c *Client) AuctionBid(amount *big.Int, slot int64, bidAmount *big.Int,
1214 deadline *big.Int) (tx *types.Transaction, err error) {
1215 c.rw.Lock()
1216 defer c.rw.Unlock()
1217 cpy := c.nextBlock().copy()
1218 defer func() { func() { c.revertIfErr(err, cpy) }() }()
1219 if c.addr == nil {
1220 return nil, eth.ErrAccountNil
1221 }
1222
1223 nextBlock := c.nextBlock()
1224 a := nextBlock.Auction
1225
1226 if slot < a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots) {
1227 return nil, errBidClosed
1228 }
1229
1230 if slot >= a.getCurrentSlotNumber()+int64(a.Vars.ClosedAuctionSlots)+int64(a.Vars.OpenAuctionSlots) {
1231 return nil, errBidNotOpen
1232 }
1233
1234 minBid, err := a.getMinBidBySlot(slot)
1235 if err != nil {
1236 return nil, err
1237 }
1238 if bidAmount.Cmp(minBid) == -1 {
1239 return nil, errBidBelowMin
1240 }
1241
1242 if _, ok := a.State.Coordinators[*c.addr]; !ok {
1243 return nil, errCoordNotReg
1244 }
1245
1246 slotState, ok := a.State.Slots[slot]
1247 if !ok {
1248 slotState = eth.NewSlotState()
1249 a.State.Slots[slot] = slotState
1250 }
1251 slotState.Bidder = *c.addr
1252 slotState.BidAmount = bidAmount
1253
1254 a.Events.NewBid = append(a.Events.NewBid,
1255 eth.AuctionEventNewBid{Slot: slot, BidAmount: bidAmount, Bidder: *c.addr})
1256
1257 type data struct {
1258 Slot int64
1259 BidAmount *big.Int
1260 Bidder ethCommon.Address
1261 }
1262 return a.addTransaction(newTransaction("bid", data{slot, bidAmount, *c.addr})), nil
1263}
1264
1265// AuctionMultiBid is the interface to call the smart contract function. This
1266// implementation behaves as if any address has infinite tokens.
1267func (c *Client) AuctionMultiBid(amount *big.Int, startingSlot int64, endingSlot int64, slotSet [6]bool,
1268 maxBid, closedMinBid, deadline *big.Int) (tx *types.Transaction, err error) {
1269 c.rw.Lock()
1270 defer c.rw.Unlock()
1271 cpy := c.nextBlock().copy()
1272 defer func() { c.revertIfErr(err, cpy) }()
1273 if c.addr == nil {
1274 return nil, eth.ErrAccountNil
1275 }
1276
1277 log.Error("TODO")
1278 return nil, errTODO
1279}
1280
1281// AuctionCanForge is the interface to call the smart contract function
1282func (c *Client) AuctionCanForge(forger ethCommon.Address, blockNum int64) (bool, error) {
1283 c.rw.RLock()
1284 defer c.rw.RUnlock()
1285
1286 currentBlock := c.currentBlock()
1287 a := currentBlock.Auction
1288 return a.canForge(forger, blockNum)
1289}
1290
1291// AuctionForge is the interface to call the smart contract function
1292func (c *Client) AuctionForge(forger ethCommon.Address) (tx *types.Transaction, err error) {
1293 c.rw.Lock()
1294 defer c.rw.Unlock()
1295 cpy := c.nextBlock().copy()
1296 defer func() { c.revertIfErr(err, cpy) }()
1297 if c.addr == nil {
1298 return nil, eth.ErrAccountNil
1299 }
1300
1301 log.Error("TODO")
1302 return nil, errTODO
1303}
1304
1305// AuctionClaimHEZ is the interface to call the smart contract function
1306func (c *Client) AuctionClaimHEZ() (tx *types.Transaction, err error) {
1307 c.rw.Lock()
1308 defer c.rw.Unlock()
1309 cpy := c.nextBlock().copy()
1310 defer func() { c.revertIfErr(err, cpy) }()
1311 if c.addr == nil {
1312 return nil, eth.ErrAccountNil
1313 }
1314
1315 log.Error("TODO")
1316 return nil, errTODO
1317}
1318
1319// AuctionGetClaimableHEZ is the interface to call the smart contract function
1320func (c *Client) AuctionGetClaimableHEZ(bidder ethCommon.Address) (*big.Int, error) {
1321 c.rw.RLock()
1322 defer c.rw.RUnlock()
1323
1324 log.Error("TODO")
1325 return nil, errTODO
1326}
1327
1328// AuctionConstants returns the Constants of the Auction Smart Contract
1329func (c *Client) AuctionConstants() (*eth.AuctionConstants, error) {
1330 c.rw.RLock()
1331 defer c.rw.RUnlock()
1332
1333 return c.auctionConstants, nil
1334}
1335
1336// AuctionEventsByBlock returns the events in a block that happened in the Auction Smart Contract
1337func (c *Client) AuctionEventsByBlock(blockNum int64) (*eth.AuctionEvents, *ethCommon.Hash, error) {
1338 c.rw.RLock()
1339 defer c.rw.RUnlock()
1340
1341 block, ok := c.blocks[blockNum]
1342 if !ok {
1343 return nil, nil, fmt.Errorf("Block %v doesn't exist", blockNum)
1344 }
1345 return &block.Auction.Events, &block.Eth.Hash, nil
1346}