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