hermez-node/eth/auction.go
eth/auction.goRaw
1package eth
2
3import (
4 "context"
5 "encoding/binary"
6 "fmt"
7 "math/big"
8 "strings"
9
10 "github.com/ethereum/go-ethereum"
11 "github.com/ethereum/go-ethereum/accounts/abi"
12 "github.com/ethereum/go-ethereum/accounts/abi/bind"
13 ethCommon "github.com/ethereum/go-ethereum/common"
14 "github.com/ethereum/go-ethereum/core/types"
15 "github.com/ethereum/go-ethereum/crypto"
16 "github.com/ethereum/go-ethereum/ethclient"
17 HermezAuctionProtocol "github.com/hermeznetwork/hermez-node/eth/contracts/auction"
18 ERC777 "github.com/hermeznetwork/hermez-node/eth/contracts/erc777"
19 "golang.org/x/crypto/sha3"
20)
21
22// AuctionConstants are the constants of the Rollup Smart Contract
23type AuctionConstants struct {
24 // Blocks per slot
25 BlocksPerSlot uint8
26 // Minimum bid when no one has bid yet
27 InitialMinimalBidding *big.Int
28 // First block where the first slot begins
29 GenesisBlockNum int64
30 // ERC777 token with which the bids will be made
31 TokenHEZ ethCommon.Address
32 // HermezRollup smartcontract address
33 HermezRollup ethCommon.Address
34 // Hermez Governanze Token smartcontract address who controls some parameters and collects HEZ fee
35 // Only for test
36 GovernanceAddress ethCommon.Address
37}
38
39// SlotState is the state of a slot
40type SlotState struct {
41 Bidder ethCommon.Address
42 Fulfilled bool
43 BidAmount *big.Int
44 ClosedMinBid *big.Int
45}
46
47// NewSlotState returns an empty SlotState
48func NewSlotState() *SlotState {
49 return &SlotState{
50 Bidder: ethCommon.Address{},
51 Fulfilled: false,
52 BidAmount: big.NewInt(0),
53 ClosedMinBid: big.NewInt(0),
54 }
55}
56
57// Coordinator is the details of the Coordinator identified by the forger address
58type Coordinator struct {
59 Forger ethCommon.Address
60 URL string
61}
62
63// AuctionVariables are the variables of the Auction Smart Contract
64type AuctionVariables struct {
65 // Boot Coordinator Address
66 DonationAddress ethCommon.Address
67 // Boot Coordinator Address
68 BootCoordinator ethCommon.Address
69 // The minimum bid value in a series of 6 slots
70 DefaultSlotSetBid [6]*big.Int
71 // Distance (#slots) to the closest slot to which you can bid ( 2 Slots = 2 * 40 Blocks = 20 min )
72 ClosedAuctionSlots uint16
73 // Distance (#slots) to the farthest slot to which you can bid (30 days = 4320 slots )
74 OpenAuctionSlots uint16
75 // How the HEZ tokens deposited by the slot winner are distributed (Burn: 40% - Donation: 40% - HGT: 20%)
76 AllocationRatio [3]uint16
77 // Minimum outbid (percentage) over the previous one to consider it valid
78 Outbidding uint16
79 // Number of blocks at the end of a slot in which any coordinator can forge if the winner has not forged one before
80 SlotDeadline uint8
81}
82
83// AuctionState represents the state of the Rollup in the Smart Contract
84type AuctionState struct {
85 // Mapping to control slot state
86 Slots map[int64]*SlotState
87 // Mapping to control balances pending to claim
88 PendingBalances map[ethCommon.Address]*big.Int
89 // Mapping to register all the coordinators. The address used for the mapping is the forger address
90 Coordinators map[ethCommon.Address]*Coordinator
91}
92
93// AuctionEventNewBid is an event of the Auction Smart Contract
94type AuctionEventNewBid struct {
95 Slot int64
96 BidAmount *big.Int
97 Bidder ethCommon.Address
98}
99
100// AuctionEventNewSlotDeadline is an event of the Auction Smart Contract
101type AuctionEventNewSlotDeadline struct {
102 NewSlotDeadline uint8
103}
104
105// AuctionEventNewClosedAuctionSlots is an event of the Auction Smart Contract
106type AuctionEventNewClosedAuctionSlots struct {
107 NewClosedAuctionSlots uint16
108}
109
110// AuctionEventNewOutbidding is an event of the Auction Smart Contract
111type AuctionEventNewOutbidding struct {
112 NewOutbidding uint16
113}
114
115// AuctionEventNewDonationAddress is an event of the Auction Smart Contract
116type AuctionEventNewDonationAddress struct {
117 NewDonationAddress ethCommon.Address
118}
119
120// AuctionEventNewBootCoordinator is an event of the Auction Smart Contract
121type AuctionEventNewBootCoordinator struct {
122 NewBootCoordinator ethCommon.Address
123}
124
125// AuctionEventNewOpenAuctionSlots is an event of the Auction Smart Contract
126type AuctionEventNewOpenAuctionSlots struct {
127 NewOpenAuctionSlots uint16
128}
129
130// AuctionEventNewAllocationRatio is an event of the Auction Smart Contract
131type AuctionEventNewAllocationRatio struct {
132 NewAllocationRatio [3]uint16
133}
134
135// AuctionEventSetCoordinator is an event of the Auction Smart Contract
136type AuctionEventSetCoordinator struct {
137 BidderAddress ethCommon.Address
138 ForgerAddress ethCommon.Address
139 CoordinatorURL string
140}
141
142// AuctionEventNewForgeAllocated is an event of the Auction Smart Contract
143type AuctionEventNewForgeAllocated struct {
144 Bidder ethCommon.Address
145 Forger ethCommon.Address
146 SlotToForge int64
147 BurnAmount *big.Int
148 DonationAmount *big.Int
149 GovernanceAmount *big.Int
150}
151
152// AuctionEventNewDefaultSlotSetBid is an event of the Auction Smart Contract
153type AuctionEventNewDefaultSlotSetBid struct {
154 SlotSet int64
155 NewInitialMinBid *big.Int
156}
157
158// AuctionEventNewForge is an event of the Auction Smart Contract
159type AuctionEventNewForge struct {
160 Forger ethCommon.Address
161 SlotToForge int64
162}
163
164// AuctionEventHEZClaimed is an event of the Auction Smart Contract
165type AuctionEventHEZClaimed struct {
166 Owner ethCommon.Address
167 Amount *big.Int
168}
169
170// AuctionEvents is the list of events in a block of the Auction Smart Contract
171type AuctionEvents struct {
172 NewBid []AuctionEventNewBid
173 NewSlotDeadline []AuctionEventNewSlotDeadline
174 NewClosedAuctionSlots []AuctionEventNewClosedAuctionSlots
175 NewOutbidding []AuctionEventNewOutbidding
176 NewDonationAddress []AuctionEventNewDonationAddress
177 NewBootCoordinator []AuctionEventNewBootCoordinator
178 NewOpenAuctionSlots []AuctionEventNewOpenAuctionSlots
179 NewAllocationRatio []AuctionEventNewAllocationRatio
180 SetCoordinator []AuctionEventSetCoordinator
181 NewForgeAllocated []AuctionEventNewForgeAllocated
182 NewDefaultSlotSetBid []AuctionEventNewDefaultSlotSetBid
183 NewForge []AuctionEventNewForge
184 HEZClaimed []AuctionEventHEZClaimed
185}
186
187// NewAuctionEvents creates an empty AuctionEvents with the slices initialized.
188func NewAuctionEvents() AuctionEvents {
189 return AuctionEvents{
190 NewBid: make([]AuctionEventNewBid, 0),
191 NewSlotDeadline: make([]AuctionEventNewSlotDeadline, 0),
192 NewClosedAuctionSlots: make([]AuctionEventNewClosedAuctionSlots, 0),
193 NewOutbidding: make([]AuctionEventNewOutbidding, 0),
194 NewDonationAddress: make([]AuctionEventNewDonationAddress, 0),
195 NewBootCoordinator: make([]AuctionEventNewBootCoordinator, 0),
196 NewOpenAuctionSlots: make([]AuctionEventNewOpenAuctionSlots, 0),
197 NewAllocationRatio: make([]AuctionEventNewAllocationRatio, 0),
198 SetCoordinator: make([]AuctionEventSetCoordinator, 0),
199 NewForgeAllocated: make([]AuctionEventNewForgeAllocated, 0),
200 NewDefaultSlotSetBid: make([]AuctionEventNewDefaultSlotSetBid, 0),
201 NewForge: make([]AuctionEventNewForge, 0),
202 HEZClaimed: make([]AuctionEventHEZClaimed, 0),
203 }
204}
205
206// AuctionInterface is the inteface to to Auction Smart Contract
207type AuctionInterface interface {
208 //
209 // Smart Contract Methods
210 //
211
212 // Getter/Setter, where Setter is onlyOwner
213 AuctionSetSlotDeadline(newDeadline uint8) (*types.Transaction, error)
214 AuctionGetSlotDeadline() (uint8, error)
215 AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (*types.Transaction, error)
216 AuctionGetOpenAuctionSlots() (uint16, error)
217 AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (*types.Transaction, error)
218 AuctionGetClosedAuctionSlots() (uint16, error)
219 AuctionSetOutbidding(newOutbidding uint16) (*types.Transaction, error)
220 AuctionGetOutbidding() (uint16, error)
221 AuctionSetAllocationRatio(newAllocationRatio [3]uint16) (*types.Transaction, error)
222 AuctionGetAllocationRatio() ([3]uint16, error)
223 AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (*types.Transaction, error)
224 AuctionGetDonationAddress() (*ethCommon.Address, error)
225 AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address) (*types.Transaction, error)
226 AuctionGetBootCoordinator() (*ethCommon.Address, error)
227 AuctionChangeDefaultSlotSetBid(slotSet int64, newInitialMinBid *big.Int) (*types.Transaction, error)
228
229 // Coordinator Management
230 AuctionSetCoordinator(forger ethCommon.Address, coordinatorURL string) (*types.Transaction, error)
231
232 // Slot Info
233 AuctionGetSlotNumber(blockNum int64) (int64, error)
234 AuctionGetCurrentSlotNumber() (int64, error)
235 AuctionGetMinBidBySlot(slot int64) (*big.Int, error)
236 AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, error)
237 AuctionGetSlotSet(slot int64) (*big.Int, error)
238
239 // Bidding
240 AuctionBid(slot int64, bidAmount *big.Int) (*types.Transaction, error)
241 AuctionMultiBid(startingSlot int64, endingSlot int64, slotSet [6]bool, maxBid, closedMinBid, budget *big.Int) (*types.Transaction, error)
242
243 // Forge
244 AuctionCanForge(forger ethCommon.Address, blockNum int64) (bool, error)
245 AuctionForge(forger ethCommon.Address) (*types.Transaction, error)
246
247 // Fees
248 AuctionClaimHEZ() (*types.Transaction, error)
249 AuctionGetClaimableHEZ(bidder ethCommon.Address) (*big.Int, error)
250
251 //
252 // Smart Contract Status
253 //
254
255 AuctionConstants() (*AuctionConstants, error)
256 AuctionEventsByBlock(blockNum int64) (*AuctionEvents, *ethCommon.Hash, error)
257}
258
259//
260// Implementation
261//
262
263// AuctionClient is the implementation of the interface to the Auction Smart Contract in ethereum.
264type AuctionClient struct {
265 client *EthereumClient
266 address ethCommon.Address
267 tokenAddress ethCommon.Address
268 gasLimit uint64
269 contractAbi abi.ABI
270}
271
272// NewAuctionClient creates a new AuctionClient. `tokenAddress` is the address of the HEZ tokens.
273func NewAuctionClient(client *EthereumClient, address, tokenAddress ethCommon.Address) (*AuctionClient, error) {
274 contractAbi, err := abi.JSON(strings.NewReader(string(HermezAuctionProtocol.HermezAuctionProtocolABI)))
275 if err != nil {
276 return nil, err
277 }
278 return &AuctionClient{
279 client: client,
280 address: address,
281 tokenAddress: tokenAddress,
282 gasLimit: 1000000, //nolint:gomnd
283 contractAbi: contractAbi,
284 }, nil
285}
286
287// AuctionSetSlotDeadline is the interface to call the smart contract function
288func (c *AuctionClient) AuctionSetSlotDeadline(newDeadline uint8) (*types.Transaction, error) {
289 var tx *types.Transaction
290 var err error
291 if tx, err = c.client.CallAuth(
292 c.gasLimit,
293 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
294 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
295 if err != nil {
296 return nil, err
297 }
298 return auction.SetSlotDeadline(auth, newDeadline)
299 },
300 ); err != nil {
301 return nil, fmt.Errorf("Failed setting slotDeadline: %w", err)
302 }
303 return tx, nil
304}
305
306// AuctionGetSlotDeadline is the interface to call the smart contract function
307func (c *AuctionClient) AuctionGetSlotDeadline() (uint8, error) {
308 var slotDeadline uint8
309 if err := c.client.Call(func(ec *ethclient.Client) error {
310 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
311 if err != nil {
312 return err
313 }
314 slotDeadline, err = auction.GetSlotDeadline(nil)
315 return err
316 }); err != nil {
317 return 0, err
318 }
319 return slotDeadline, nil
320}
321
322// AuctionSetOpenAuctionSlots is the interface to call the smart contract function
323func (c *AuctionClient) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (*types.Transaction, error) {
324 var tx *types.Transaction
325 var err error
326 if tx, err = c.client.CallAuth(
327 c.gasLimit,
328 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
329 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
330 if err != nil {
331 return nil, err
332 }
333 return auction.SetOpenAuctionSlots(auth, newOpenAuctionSlots)
334 },
335 ); err != nil {
336 return nil, fmt.Errorf("Failed setting openAuctionSlots: %w", err)
337 }
338 return tx, nil
339}
340
341// AuctionGetOpenAuctionSlots is the interface to call the smart contract function
342func (c *AuctionClient) AuctionGetOpenAuctionSlots() (uint16, error) {
343 var openAuctionSlots uint16
344 if err := c.client.Call(func(ec *ethclient.Client) error {
345 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
346 if err != nil {
347 return err
348 }
349 openAuctionSlots, err = auction.GetOpenAuctionSlots(nil)
350 return err
351 }); err != nil {
352 return 0, err
353 }
354 return openAuctionSlots, nil
355}
356
357// AuctionSetClosedAuctionSlots is the interface to call the smart contract function
358func (c *AuctionClient) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (*types.Transaction, error) {
359 var tx *types.Transaction
360 var err error
361 if tx, err = c.client.CallAuth(
362 c.gasLimit,
363 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
364 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
365 if err != nil {
366 return nil, err
367 }
368 return auction.SetClosedAuctionSlots(auth, newClosedAuctionSlots)
369 },
370 ); err != nil {
371 return nil, fmt.Errorf("Failed setting closedAuctionSlots: %w", err)
372 }
373 return tx, nil
374}
375
376// AuctionGetClosedAuctionSlots is the interface to call the smart contract function
377func (c *AuctionClient) AuctionGetClosedAuctionSlots() (uint16, error) {
378 var closedAuctionSlots uint16
379 if err := c.client.Call(func(ec *ethclient.Client) error {
380 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
381 if err != nil {
382 return err
383 }
384 closedAuctionSlots, err = auction.GetClosedAuctionSlots(nil)
385 return err
386 }); err != nil {
387 return 0, err
388 }
389 return closedAuctionSlots, nil
390}
391
392// AuctionSetOutbidding is the interface to call the smart contract function
393func (c *AuctionClient) AuctionSetOutbidding(newOutbidding uint16) (*types.Transaction, error) {
394 var tx *types.Transaction
395 var err error
396 if tx, err = c.client.CallAuth(
397 12500000, //nolint:gomnd
398 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
399 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
400 if err != nil {
401 return nil, err
402 }
403 return auction.SetOutbidding(auth, newOutbidding)
404 },
405 ); err != nil {
406 return nil, fmt.Errorf("Failed setting setOutbidding: %w", err)
407 }
408 return tx, nil
409}
410
411// AuctionGetOutbidding is the interface to call the smart contract function
412func (c *AuctionClient) AuctionGetOutbidding() (uint16, error) {
413 var outbidding uint16
414 if err := c.client.Call(func(ec *ethclient.Client) error {
415 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
416 if err != nil {
417 return err
418 }
419 outbidding, err = auction.GetOutbidding(nil)
420 return err
421 }); err != nil {
422 return 0, err
423 }
424 return outbidding, nil
425}
426
427// AuctionSetAllocationRatio is the interface to call the smart contract function
428func (c *AuctionClient) AuctionSetAllocationRatio(newAllocationRatio [3]uint16) (*types.Transaction, error) {
429 var tx *types.Transaction
430 var err error
431 if tx, err = c.client.CallAuth(
432 c.gasLimit,
433 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
434 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
435 if err != nil {
436 return nil, err
437 }
438 return auction.SetAllocationRatio(auth, newAllocationRatio)
439 },
440 ); err != nil {
441 return nil, fmt.Errorf("Failed setting allocationRatio: %w", err)
442 }
443 return tx, nil
444}
445
446// AuctionGetAllocationRatio is the interface to call the smart contract function
447func (c *AuctionClient) AuctionGetAllocationRatio() ([3]uint16, error) {
448 var allocationRation [3]uint16
449 if err := c.client.Call(func(ec *ethclient.Client) error {
450 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
451 if err != nil {
452 return err
453 }
454 allocationRation, err = auction.GetAllocationRatio(nil)
455 return err
456 }); err != nil {
457 return [3]uint16{}, err
458 }
459 return allocationRation, nil
460}
461
462// AuctionSetDonationAddress is the interface to call the smart contract function
463func (c *AuctionClient) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) (*types.Transaction, error) {
464 var tx *types.Transaction
465 var err error
466 if tx, err = c.client.CallAuth(
467 c.gasLimit,
468 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
469 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
470 if err != nil {
471 return nil, err
472 }
473 return auction.SetDonationAddress(auth, newDonationAddress)
474 },
475 ); err != nil {
476 return nil, fmt.Errorf("Failed setting donationAddress: %w", err)
477 }
478 return tx, nil
479}
480
481// AuctionGetDonationAddress is the interface to call the smart contract function
482func (c *AuctionClient) AuctionGetDonationAddress() (*ethCommon.Address, error) {
483 var donationAddress ethCommon.Address
484 if err := c.client.Call(func(ec *ethclient.Client) error {
485 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
486 if err != nil {
487 return err
488 }
489 donationAddress, err = auction.GetDonationAddress(nil)
490 return err
491 }); err != nil {
492 return nil, err
493 }
494 return &donationAddress, nil
495}
496
497// AuctionSetBootCoordinator is the interface to call the smart contract function
498func (c *AuctionClient) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address) (*types.Transaction, error) {
499 var tx *types.Transaction
500 var err error
501 if tx, err = c.client.CallAuth(
502 c.gasLimit,
503 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
504 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
505 if err != nil {
506 return nil, err
507 }
508 return auction.SetBootCoordinator(auth, newBootCoordinator)
509 },
510 ); err != nil {
511 return nil, fmt.Errorf("Failed setting bootCoordinator: %w", err)
512 }
513 return tx, nil
514}
515
516// AuctionGetBootCoordinator is the interface to call the smart contract function
517func (c *AuctionClient) AuctionGetBootCoordinator() (*ethCommon.Address, error) {
518 var bootCoordinator ethCommon.Address
519 if err := c.client.Call(func(ec *ethclient.Client) error {
520 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
521 if err != nil {
522 return err
523 }
524 bootCoordinator, err = auction.GetBootCoordinator(nil)
525 return err
526 }); err != nil {
527 return nil, err
528 }
529 return &bootCoordinator, nil
530}
531
532// AuctionChangeDefaultSlotSetBid is the interface to call the smart contract function
533func (c *AuctionClient) AuctionChangeDefaultSlotSetBid(slotSet int64, newInitialMinBid *big.Int) (*types.Transaction, error) {
534 var tx *types.Transaction
535 var err error
536 if tx, err = c.client.CallAuth(
537 c.gasLimit,
538 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
539 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
540 if err != nil {
541 return nil, err
542 }
543 slotSetToSend := big.NewInt(slotSet)
544 return auction.ChangeDefaultSlotSetBid(auth, slotSetToSend, newInitialMinBid)
545 },
546 ); err != nil {
547 return nil, fmt.Errorf("Failed changing slotSet Bid: %w", err)
548 }
549 return tx, nil
550}
551
552// AuctionGetClaimableHEZ is the interface to call the smart contract function
553func (c *AuctionClient) AuctionGetClaimableHEZ(claimAddress ethCommon.Address) (*big.Int, error) {
554 var claimableHEZ *big.Int
555 if err := c.client.Call(func(ec *ethclient.Client) error {
556 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
557 if err != nil {
558 return err
559 }
560 claimableHEZ, err = auction.GetClaimableHEZ(nil, claimAddress)
561 return err
562 }); err != nil {
563 return nil, err
564 }
565 return claimableHEZ, nil
566}
567
568// AuctionSetCoordinator is the interface to call the smart contract function
569func (c *AuctionClient) AuctionSetCoordinator(forger ethCommon.Address, coordinatorURL string) (*types.Transaction, error) {
570 var tx *types.Transaction
571 var err error
572 if tx, err = c.client.CallAuth(
573 c.gasLimit,
574 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
575 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
576 if err != nil {
577 return nil, err
578 }
579 return auction.SetCoordinator(auth, forger, coordinatorURL)
580 },
581 ); err != nil {
582 return nil, fmt.Errorf("Failed set coordinator: %w", err)
583 }
584 return tx, nil
585}
586
587// AuctionGetCurrentSlotNumber is the interface to call the smart contract function
588func (c *AuctionClient) AuctionGetCurrentSlotNumber() (int64, error) {
589 var _currentSlotNumber *big.Int
590 if err := c.client.Call(func(ec *ethclient.Client) error {
591 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
592 if err != nil {
593 return err
594 }
595 _currentSlotNumber, err = auction.GetCurrentSlotNumber(nil)
596 return err
597 }); err != nil {
598 return 0, err
599 }
600 currentSlotNumber := _currentSlotNumber.Int64()
601 return currentSlotNumber, nil
602}
603
604// AuctionGetMinBidBySlot is the interface to call the smart contract function
605func (c *AuctionClient) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) {
606 var minBid *big.Int
607 if err := c.client.Call(func(ec *ethclient.Client) error {
608 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
609 if err != nil {
610 return err
611 }
612 slotToSend := big.NewInt(slot)
613 minBid, err = auction.GetMinBidBySlot(nil, slotToSend)
614 return err
615 }); err != nil {
616 return big.NewInt(0), err
617 }
618 return minBid, nil
619}
620
621// AuctionGetSlotSet is the interface to call the smart contract function
622func (c *AuctionClient) AuctionGetSlotSet(slot int64) (*big.Int, error) {
623 var slotSet *big.Int
624 if err := c.client.Call(func(ec *ethclient.Client) error {
625 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
626 if err != nil {
627 return err
628 }
629 slotToSend := big.NewInt(slot)
630 slotSet, err = auction.GetSlotSet(nil, slotToSend)
631 return err
632 }); err != nil {
633 return big.NewInt(0), err
634 }
635 return slotSet, nil
636}
637
638// AuctionGetDefaultSlotSetBid is the interface to call the smart contract function
639func (c *AuctionClient) AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, error) {
640 var minBidSlotSet *big.Int
641 if err := c.client.Call(func(ec *ethclient.Client) error {
642 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
643 if err != nil {
644 return err
645 }
646 minBidSlotSet, err = auction.GetDefaultSlotSetBid(nil, slotSet)
647 return err
648 }); err != nil {
649 return big.NewInt(0), err
650 }
651 return minBidSlotSet, nil
652}
653
654// AuctionGetSlotNumber is the interface to call the smart contract function
655func (c *AuctionClient) AuctionGetSlotNumber(blockNum int64) (int64, error) {
656 var slot *big.Int
657 if err := c.client.Call(func(ec *ethclient.Client) error {
658 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
659 if err != nil {
660 return err
661 }
662 blockNumBig := big.NewInt(blockNum)
663 slot, err = auction.GetSlotNumber(nil, blockNumBig)
664 return err
665 }); err != nil {
666 return 0, err
667 }
668 return slot.Int64(), nil
669}
670
671// AuctionBid is the interface to call the smart contract function
672func (c *AuctionClient) AuctionBid(slot int64, bidAmount *big.Int) (*types.Transaction, error) {
673 var tx *types.Transaction
674 var err error
675 if tx, err = c.client.CallAuth(
676 c.gasLimit,
677 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
678 tokens, err := ERC777.NewERC777(c.tokenAddress, ec)
679 if err != nil {
680 return nil, err
681 }
682 bidFnSignature := []byte("bid(uint128,uint128)")
683 hash := sha3.NewLegacyKeccak256()
684 _, err = hash.Write(bidFnSignature)
685 if err != nil {
686 return nil, err
687 }
688 methodID := hash.Sum(nil)[:4]
689 slotBytes := make([]byte, 8)
690 binary.BigEndian.PutUint64(slotBytes, uint64(slot))
691 paddedSlot := ethCommon.LeftPadBytes(slotBytes, 32)
692 paddedAmount := ethCommon.LeftPadBytes(bidAmount.Bytes(), 32)
693 var userData []byte
694 userData = append(userData, methodID...)
695 userData = append(userData, paddedSlot...)
696 userData = append(userData, paddedAmount...)
697 return tokens.Send(auth, c.address, bidAmount, userData)
698 },
699 ); err != nil {
700 return nil, fmt.Errorf("Failed bid: %w", err)
701 }
702 return tx, nil
703}
704
705// AuctionMultiBid is the interface to call the smart contract function
706func (c *AuctionClient) AuctionMultiBid(startingSlot int64, endingSlot int64, slotSet [6]bool, maxBid, closedMinBid, budget *big.Int) (*types.Transaction, error) {
707 var tx *types.Transaction
708 var err error
709 if tx, err = c.client.CallAuth(
710 c.gasLimit,
711 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
712 tokens, err := ERC777.NewERC777(c.tokenAddress, ec)
713 if err != nil {
714 return nil, err
715 }
716 multiBidFnSignature := []byte("multiBid(uint128,uint128,bool[6],uint128,uint128)")
717 hash := sha3.NewLegacyKeccak256()
718 _, err = hash.Write(multiBidFnSignature)
719 if err != nil {
720 return nil, err
721 }
722 methodID := hash.Sum(nil)[:4]
723 startingSlotBytes := make([]byte, 8)
724 binary.BigEndian.PutUint64(startingSlotBytes, uint64(startingSlot))
725 paddedStartingSlot := ethCommon.LeftPadBytes(startingSlotBytes, 32)
726 endingSlotBytes := make([]byte, 8)
727 binary.BigEndian.PutUint64(endingSlotBytes, uint64(endingSlot))
728 paddedEndingSlot := ethCommon.LeftPadBytes(endingSlotBytes, 32)
729 paddedMinBid := ethCommon.LeftPadBytes(closedMinBid.Bytes(), 32)
730 paddedMaxBid := ethCommon.LeftPadBytes(maxBid.Bytes(), 32)
731 var userData []byte
732 userData = append(userData, methodID...)
733 userData = append(userData, paddedStartingSlot...)
734 userData = append(userData, paddedEndingSlot...)
735 for i := 0; i < len(slotSet); i++ {
736 if slotSet[i] {
737 paddedSlotSet := ethCommon.LeftPadBytes([]byte{1}, 32)
738 userData = append(userData, paddedSlotSet...)
739 } else {
740 paddedSlotSet := ethCommon.LeftPadBytes([]byte{0}, 32)
741 userData = append(userData, paddedSlotSet...)
742 }
743 }
744 userData = append(userData, paddedMaxBid...)
745 userData = append(userData, paddedMinBid...)
746 return tokens.Send(auth, c.address, budget, userData)
747 },
748 ); err != nil {
749 return nil, fmt.Errorf("Failed multibid: %w", err)
750 }
751 return tx, nil
752}
753
754// AuctionCanForge is the interface to call the smart contract function
755func (c *AuctionClient) AuctionCanForge(forger ethCommon.Address, blockNum int64) (bool, error) {
756 var canForge bool
757 if err := c.client.Call(func(ec *ethclient.Client) error {
758 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
759 if err != nil {
760 return err
761 }
762 canForge, err = auction.CanForge(nil, forger, big.NewInt(blockNum))
763 return err
764 }); err != nil {
765 return false, err
766 }
767 return canForge, nil
768}
769
770// AuctionClaimHEZ is the interface to call the smart contract function
771func (c *AuctionClient) AuctionClaimHEZ() (*types.Transaction, error) {
772 var tx *types.Transaction
773 var err error
774 if tx, err = c.client.CallAuth(
775 c.gasLimit,
776 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
777 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
778 if err != nil {
779 return nil, err
780 }
781 return auction.ClaimHEZ(auth)
782 },
783 ); err != nil {
784 return nil, fmt.Errorf("Failed claim HEZ: %w", err)
785 }
786 return tx, nil
787}
788
789// AuctionForge is the interface to call the smart contract function
790func (c *AuctionClient) AuctionForge(forger ethCommon.Address) (*types.Transaction, error) {
791 var tx *types.Transaction
792 var err error
793 if tx, err = c.client.CallAuth(
794 c.gasLimit,
795 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
796 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
797 if err != nil {
798 return nil, err
799 }
800 return auction.Forge(auth, forger)
801 },
802 ); err != nil {
803 return nil, fmt.Errorf("Failed forge: %w", err)
804 }
805 return tx, nil
806}
807
808// AuctionConstants returns the Constants of the Auction Smart Contract
809func (c *AuctionClient) AuctionConstants() (*AuctionConstants, error) {
810 auctionConstants := new(AuctionConstants)
811 if err := c.client.Call(func(ec *ethclient.Client) error {
812 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
813 if err != nil {
814 return err
815 }
816 auctionConstants.BlocksPerSlot, err = auction.BLOCKSPERSLOT(nil)
817 if err != nil {
818 return err
819 }
820 genesisBlock, err := auction.GenesisBlock(nil)
821 if err != nil {
822 return err
823 }
824 auctionConstants.GenesisBlockNum = genesisBlock.Int64()
825 auctionConstants.HermezRollup, err = auction.HermezRollup(nil)
826 if err != nil {
827 return err
828 }
829 auctionConstants.InitialMinimalBidding, err = auction.INITIALMINIMALBIDDING(nil)
830 if err != nil {
831 return err
832 }
833 auctionConstants.TokenHEZ, err = auction.TokenHEZ(nil)
834 return err
835 }); err != nil {
836 return nil, err
837 }
838 return auctionConstants, nil
839}
840
841// AuctionVariables returns the variables of the Auction Smart Contract
842func (c *AuctionClient) AuctionVariables() (*AuctionVariables, error) {
843 auctionVariables := new(AuctionVariables)
844 if err := c.client.Call(func(ec *ethclient.Client) error {
845 var err error
846 auctionVariables.AllocationRatio, err = c.AuctionGetAllocationRatio()
847 if err != nil {
848 return err
849 }
850 bootCoordinator, err := c.AuctionGetBootCoordinator()
851 if err != nil {
852 return err
853 }
854 auctionVariables.BootCoordinator = *bootCoordinator
855 auctionVariables.ClosedAuctionSlots, err = c.AuctionGetClosedAuctionSlots()
856 if err != nil {
857 return err
858 }
859 var defaultSlotSetBid [6]*big.Int
860 for i := uint8(0); i < 6; i++ {
861 bid, err := c.AuctionGetDefaultSlotSetBid(i)
862 if err != nil {
863 return err
864 }
865 defaultSlotSetBid[i] = bid
866 }
867 auctionVariables.DefaultSlotSetBid = defaultSlotSetBid
868 donationAddress, err := c.AuctionGetDonationAddress()
869 if err != nil {
870 return err
871 }
872 auctionVariables.DonationAddress = *donationAddress
873 auctionVariables.OpenAuctionSlots, err = c.AuctionGetOpenAuctionSlots()
874 if err != nil {
875 return err
876 }
877 auctionVariables.Outbidding, err = c.AuctionGetOutbidding()
878 if err != nil {
879 return err
880 }
881 auctionVariables.SlotDeadline, err = c.AuctionGetSlotDeadline()
882 return err
883 }); err != nil {
884 return nil, err
885 }
886 return auctionVariables, nil
887}
888
889var (
890 logAuctionNewBid = crypto.Keccak256Hash([]byte("NewBid(uint128,uint128,address)"))
891 logAuctionNewSlotDeadline = crypto.Keccak256Hash([]byte("NewSlotDeadline(uint8)"))
892 logAuctionNewClosedAuctionSlots = crypto.Keccak256Hash([]byte("NewClosedAuctionSlots(uint16)"))
893 logAuctionNewOutbidding = crypto.Keccak256Hash([]byte("NewOutbidding(uint16)"))
894 logAuctionNewDonationAddress = crypto.Keccak256Hash([]byte("NewDonationAddress(address)"))
895 logAuctionNewBootCoordinator = crypto.Keccak256Hash([]byte("NewBootCoordinator(address)"))
896 logAuctionNewOpenAuctionSlots = crypto.Keccak256Hash([]byte("NewOpenAuctionSlots(uint16)"))
897 logAuctionNewAllocationRatio = crypto.Keccak256Hash([]byte("NewAllocationRatio(uint16[3])"))
898 logAuctionSetCoordinator = crypto.Keccak256Hash([]byte("SetCoordinator(address,address,string)"))
899 logAuctionNewForgeAllocated = crypto.Keccak256Hash([]byte("NewForgeAllocated(address,address,uint128,uint128,uint128,uint128)"))
900 logAuctionNewDefaultSlotSetBid = crypto.Keccak256Hash([]byte("NewDefaultSlotSetBid(uint128,uint128)"))
901 logAuctionNewForge = crypto.Keccak256Hash([]byte("NewForge(address,uint128)"))
902 logAuctionHEZClaimed = crypto.Keccak256Hash([]byte("HEZClaimed(address,uint128)"))
903)
904
905// AuctionEventsByBlock returns the events in a block that happened in the
906// Auction Smart Contract and the blockHash where the eents happened. If there
907// are no events in that block, blockHash is nil.
908func (c *AuctionClient) AuctionEventsByBlock(blockNum int64) (*AuctionEvents, *ethCommon.Hash, error) {
909 var auctionEvents AuctionEvents
910 var blockHash ethCommon.Hash
911
912 query := ethereum.FilterQuery{
913 FromBlock: big.NewInt(blockNum),
914 ToBlock: big.NewInt(blockNum),
915 Addresses: []ethCommon.Address{
916 c.address,
917 },
918 Topics: [][]ethCommon.Hash{},
919 }
920
921 logs, err := c.client.client.FilterLogs(context.TODO(), query)
922 if err != nil {
923 return nil, nil, err
924 }
925 if len(logs) > 0 {
926 blockHash = logs[0].BlockHash
927 }
928 for _, vLog := range logs {
929 if vLog.BlockHash != blockHash {
930 return nil, nil, ErrBlockHashMismatchEvent
931 }
932 switch vLog.Topics[0] {
933 case logAuctionNewBid:
934 var auxNewBid struct {
935 Slot *big.Int
936 BidAmount *big.Int
937 Address ethCommon.Address
938 }
939 var newBid AuctionEventNewBid
940 if err := c.contractAbi.Unpack(&auxNewBid, "NewBid", vLog.Data); err != nil {
941 return nil, nil, err
942 }
943 newBid.BidAmount = auxNewBid.BidAmount
944 newBid.Slot = new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
945 newBid.Bidder = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
946 auctionEvents.NewBid = append(auctionEvents.NewBid, newBid)
947 case logAuctionNewSlotDeadline:
948 var newSlotDeadline AuctionEventNewSlotDeadline
949 if err := c.contractAbi.Unpack(&newSlotDeadline, "NewSlotDeadline", vLog.Data); err != nil {
950 return nil, nil, err
951 }
952 auctionEvents.NewSlotDeadline = append(auctionEvents.NewSlotDeadline, newSlotDeadline)
953 case logAuctionNewClosedAuctionSlots:
954 var newClosedAuctionSlots AuctionEventNewClosedAuctionSlots
955 if err := c.contractAbi.Unpack(&newClosedAuctionSlots, "NewClosedAuctionSlots", vLog.Data); err != nil {
956 return nil, nil, err
957 }
958 auctionEvents.NewClosedAuctionSlots = append(auctionEvents.NewClosedAuctionSlots, newClosedAuctionSlots)
959 case logAuctionNewOutbidding:
960 var newOutbidding AuctionEventNewOutbidding
961 if err := c.contractAbi.Unpack(&newOutbidding, "NewOutbidding", vLog.Data); err != nil {
962 return nil, nil, err
963 }
964 auctionEvents.NewOutbidding = append(auctionEvents.NewOutbidding, newOutbidding)
965 case logAuctionNewDonationAddress:
966 var newDonationAddress AuctionEventNewDonationAddress
967 newDonationAddress.NewDonationAddress = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
968 auctionEvents.NewDonationAddress = append(auctionEvents.NewDonationAddress, newDonationAddress)
969 case logAuctionNewBootCoordinator:
970 var newBootCoordinator AuctionEventNewBootCoordinator
971 newBootCoordinator.NewBootCoordinator = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
972 auctionEvents.NewBootCoordinator = append(auctionEvents.NewBootCoordinator, newBootCoordinator)
973 case logAuctionNewOpenAuctionSlots:
974 var newOpenAuctionSlots AuctionEventNewOpenAuctionSlots
975 if err := c.contractAbi.Unpack(&newOpenAuctionSlots, "NewOpenAuctionSlots", vLog.Data); err != nil {
976 return nil, nil, err
977 }
978 auctionEvents.NewOpenAuctionSlots = append(auctionEvents.NewOpenAuctionSlots, newOpenAuctionSlots)
979 case logAuctionNewAllocationRatio:
980 var newAllocationRatio AuctionEventNewAllocationRatio
981 if err := c.contractAbi.Unpack(&newAllocationRatio, "NewAllocationRatio", vLog.Data); err != nil {
982 return nil, nil, err
983 }
984 auctionEvents.NewAllocationRatio = append(auctionEvents.NewAllocationRatio, newAllocationRatio)
985 case logAuctionSetCoordinator:
986 var setCoordinator AuctionEventSetCoordinator
987 if err := c.contractAbi.Unpack(&setCoordinator, "SetCoordinator", vLog.Data); err != nil {
988 return nil, nil, err
989 }
990 setCoordinator.BidderAddress = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
991 setCoordinator.ForgerAddress = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
992 auctionEvents.SetCoordinator = append(auctionEvents.SetCoordinator, setCoordinator)
993 case logAuctionNewForgeAllocated:
994 var newForgeAllocated AuctionEventNewForgeAllocated
995 if err := c.contractAbi.Unpack(&newForgeAllocated, "NewForgeAllocated", vLog.Data); err != nil {
996 return nil, nil, err
997 }
998 newForgeAllocated.Bidder = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
999 newForgeAllocated.Forger = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
1000 newForgeAllocated.SlotToForge = new(big.Int).SetBytes(vLog.Topics[3][:]).Int64()
1001 auctionEvents.NewForgeAllocated = append(auctionEvents.NewForgeAllocated, newForgeAllocated)
1002 case logAuctionNewDefaultSlotSetBid:
1003 var auxNewDefaultSlotSetBid struct {
1004 SlotSet *big.Int
1005 NewInitialMinBid *big.Int
1006 }
1007 var newDefaultSlotSetBid AuctionEventNewDefaultSlotSetBid
1008 if err := c.contractAbi.Unpack(&auxNewDefaultSlotSetBid, "NewDefaultSlotSetBid", vLog.Data); err != nil {
1009 return nil, nil, err
1010 }
1011 newDefaultSlotSetBid.NewInitialMinBid = auxNewDefaultSlotSetBid.NewInitialMinBid
1012 newDefaultSlotSetBid.SlotSet = auxNewDefaultSlotSetBid.SlotSet.Int64()
1013 auctionEvents.NewDefaultSlotSetBid = append(auctionEvents.NewDefaultSlotSetBid, newDefaultSlotSetBid)
1014 case logAuctionNewForge:
1015 var newForge AuctionEventNewForge
1016 newForge.Forger = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
1017 newForge.SlotToForge = new(big.Int).SetBytes(vLog.Topics[2][:]).Int64()
1018 auctionEvents.NewForge = append(auctionEvents.NewForge, newForge)
1019 case logAuctionHEZClaimed:
1020 var HEZClaimed AuctionEventHEZClaimed
1021 if err := c.contractAbi.Unpack(&HEZClaimed, "HEZClaimed", vLog.Data); err != nil {
1022 return nil, nil, err
1023 }
1024 HEZClaimed.Owner = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
1025 auctionEvents.HEZClaimed = append(auctionEvents.HEZClaimed, HEZClaimed)
1026 }
1027 }
1028 return &auctionEvents, &blockHash, nil
1029}