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, error) {
285 contractAbi, err := abi.JSON(strings.NewReader(string(HermezAuctionProtocol.HermezAuctionProtocolABI)))
286 if err != nil {
287 return nil, err
288 }
289 return &AuctionClient{
290 client: client,
291 address: address,
292 tokenAddress: tokenAddress,
293 gasLimit: 1000000, //nolint:gomnd
294 contractAbi: contractAbi,
295 }, nil
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// AuctionForge is the interface to call the smart contract function
845func (c *AuctionClient) AuctionForge(forger ethCommon.Address) (*types.Transaction, error) {
846 var tx *types.Transaction
847 var err error
848 if tx, err = c.client.CallAuth(
849 c.gasLimit,
850 func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
851 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
852 if err != nil {
853 return nil, err
854 }
855 return auction.Forge(auth, forger)
856 },
857 ); err != nil {
858 return nil, fmt.Errorf("Failed forge: %w", err)
859 }
860 return tx, nil
861}
862
863// AuctionConstants returns the Constants of the Auction Smart Contract
864func (c *AuctionClient) AuctionConstants() (*AuctionConstants, error) {
865 auctionConstants := new(AuctionConstants)
866 if err := c.client.Call(func(ec *ethclient.Client) error {
867 auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec)
868 if err != nil {
869 return err
870 }
871 auctionConstants.BlocksPerSlot, err = auction.BLOCKSPERSLOT(nil)
872 if err != nil {
873 return err
874 }
875 genesisBlock, err := auction.GenesisBlock(nil)
876 if err != nil {
877 return err
878 }
879 auctionConstants.GenesisBlockNum = genesisBlock.Int64()
880 auctionConstants.HermezRollup, err = auction.HermezRollup(nil)
881 if err != nil {
882 return err
883 }
884 auctionConstants.InitialMinimalBidding, err = auction.INITIALMINIMALBIDDING(nil)
885 if err != nil {
886 return err
887 }
888 auctionConstants.TokenHEZ, err = auction.TokenHEZ(nil)
889 return err
890 }); err != nil {
891 return nil, err
892 }
893 return auctionConstants, nil
894}
895
896// AuctionVariables returns the variables of the Auction Smart Contract
897func (c *AuctionClient) AuctionVariables() (*AuctionVariables, error) {
898 auctionVariables := new(AuctionVariables)
899 if err := c.client.Call(func(ec *ethclient.Client) error {
900 var err error
901 auctionVariables.AllocationRatio, err = c.AuctionGetAllocationRatio()
902 if err != nil {
903 return err
904 }
905 bootCoordinator, err := c.AuctionGetBootCoordinator()
906 if err != nil {
907 return err
908 }
909 auctionVariables.BootCoordinator = *bootCoordinator
910 auctionVariables.ClosedAuctionSlots, err = c.AuctionGetClosedAuctionSlots()
911 if err != nil {
912 return err
913 }
914 var defaultSlotSetBid [6]*big.Int
915 for i := uint8(0); i < 6; i++ {
916 bid, err := c.AuctionGetDefaultSlotSetBid(i)
917 if err != nil {
918 return err
919 }
920 defaultSlotSetBid[i] = bid
921 }
922 auctionVariables.DefaultSlotSetBid = defaultSlotSetBid
923 donationAddress, err := c.AuctionGetDonationAddress()
924 if err != nil {
925 return err
926 }
927 auctionVariables.DonationAddress = *donationAddress
928 auctionVariables.OpenAuctionSlots, err = c.AuctionGetOpenAuctionSlots()
929 if err != nil {
930 return err
931 }
932 auctionVariables.Outbidding, err = c.AuctionGetOutbidding()
933 if err != nil {
934 return err
935 }
936 auctionVariables.SlotDeadline, err = c.AuctionGetSlotDeadline()
937 return err
938 }); err != nil {
939 return nil, err
940 }
941 return auctionVariables, nil
942}
943
944var (
945 logNewBid = crypto.Keccak256Hash([]byte("NewBid(uint128,uint128,address)"))
946 logNewSlotDeadline = crypto.Keccak256Hash([]byte("NewSlotDeadline(uint8)"))
947 logNewClosedAuctionSlots = crypto.Keccak256Hash([]byte("NewClosedAuctionSlots(uint16)"))
948 logNewOutbidding = crypto.Keccak256Hash([]byte("NewOutbidding(uint16)"))
949 logNewDonationAddress = crypto.Keccak256Hash([]byte("NewDonationAddress(address)"))
950 logNewBootCoordinator = crypto.Keccak256Hash([]byte("NewBootCoordinator(address)"))
951 logNewOpenAuctionSlots = crypto.Keccak256Hash([]byte("NewOpenAuctionSlots(uint16)"))
952 logNewAllocationRatio = crypto.Keccak256Hash([]byte("NewAllocationRatio(uint16[3])"))
953 logNewCoordinator = crypto.Keccak256Hash([]byte("NewCoordinator(address,address,string)"))
954 logCoordinatorUpdated = crypto.Keccak256Hash([]byte("CoordinatorUpdated(address,address,string)"))
955 logNewForgeAllocated = crypto.Keccak256Hash([]byte("NewForgeAllocated(address,uint128,uint128,uint128,uint128)"))
956 logNewDefaultSlotSetBid = crypto.Keccak256Hash([]byte("NewDefaultSlotSetBid(uint128,uint128)"))
957 logNewForge = crypto.Keccak256Hash([]byte("NewForge(address,uint128)"))
958 logHEZClaimed = crypto.Keccak256Hash([]byte("HEZClaimed(address,uint128)"))
959)
960
961// AuctionEventsByBlock returns the events in a block that happened in the
962// Auction Smart Contract and the blockHash where the eents happened. If there
963// are no events in that block, blockHash is nil.
964func (c *AuctionClient) AuctionEventsByBlock(blockNum int64) (*AuctionEvents, *ethCommon.Hash, error) {
965 var auctionEvents AuctionEvents
966 var blockHash ethCommon.Hash
967
968 query := ethereum.FilterQuery{
969 FromBlock: big.NewInt(blockNum),
970 ToBlock: big.NewInt(blockNum),
971 Addresses: []ethCommon.Address{
972 c.address,
973 },
974 Topics: [][]ethCommon.Hash{},
975 }
976
977 logs, err := c.client.client.FilterLogs(context.TODO(), query)
978 if err != nil {
979 return nil, nil, err
980 }
981 if len(logs) > 0 {
982 blockHash = logs[0].BlockHash
983 }
984 for _, vLog := range logs {
985 if vLog.BlockHash != blockHash {
986 return nil, nil, ErrBlockHashMismatchEvent
987 }
988 switch vLog.Topics[0] {
989 case logNewBid:
990 var auxNewBid struct {
991 Slot *big.Int
992 BidAmount *big.Int
993 Address ethCommon.Address
994 }
995 var newBid AuctionEventNewBid
996 if err := c.contractAbi.Unpack(&auxNewBid, "NewBid", vLog.Data); err != nil {
997 return nil, nil, err
998 }
999 newBid.BidAmount = auxNewBid.BidAmount
1000 newBid.Slot = new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
1001 newBid.CoordinatorForger = ethCommon.BytesToAddress(vLog.Topics[2].Bytes())
1002 auctionEvents.NewBid = append(auctionEvents.NewBid, newBid)
1003 case logNewSlotDeadline:
1004 var newSlotDeadline AuctionEventNewSlotDeadline
1005 if err := c.contractAbi.Unpack(&newSlotDeadline, "NewSlotDeadline", vLog.Data); err != nil {
1006 return nil, nil, err
1007 }
1008 auctionEvents.NewSlotDeadline = append(auctionEvents.NewSlotDeadline, newSlotDeadline)
1009 case logNewClosedAuctionSlots:
1010 var newClosedAuctionSlots AuctionEventNewClosedAuctionSlots
1011 if err := c.contractAbi.Unpack(&newClosedAuctionSlots, "NewClosedAuctionSlots", vLog.Data); err != nil {
1012 return nil, nil, err
1013 }
1014 auctionEvents.NewClosedAuctionSlots = append(auctionEvents.NewClosedAuctionSlots, newClosedAuctionSlots)
1015 case logNewOutbidding:
1016 var newOutbidding AuctionEventNewOutbidding
1017 if err := c.contractAbi.Unpack(&newOutbidding, "NewOutbidding", vLog.Data); err != nil {
1018 return nil, nil, err
1019 }
1020 auctionEvents.NewOutbidding = append(auctionEvents.NewOutbidding, newOutbidding)
1021 case logNewDonationAddress:
1022 var newDonationAddress AuctionEventNewDonationAddress
1023 if err := c.contractAbi.Unpack(&newDonationAddress, "NewDonationAddress", vLog.Data); err != nil {
1024 return nil, nil, err
1025 }
1026 auctionEvents.NewDonationAddress = append(auctionEvents.NewDonationAddress, newDonationAddress)
1027 case logNewBootCoordinator:
1028 var newBootCoordinator AuctionEventNewBootCoordinator
1029 if err := c.contractAbi.Unpack(&newBootCoordinator, "NewBootCoordinator", vLog.Data); err != nil {
1030 return nil, nil, err
1031 }
1032 auctionEvents.NewBootCoordinator = append(auctionEvents.NewBootCoordinator, newBootCoordinator)
1033 case logNewOpenAuctionSlots:
1034 var newOpenAuctionSlots AuctionEventNewOpenAuctionSlots
1035 if err := c.contractAbi.Unpack(&newOpenAuctionSlots, "NewOpenAuctionSlots", vLog.Data); err != nil {
1036 return nil, nil, err
1037 }
1038 auctionEvents.NewOpenAuctionSlots = append(auctionEvents.NewOpenAuctionSlots, newOpenAuctionSlots)
1039 case logNewAllocationRatio:
1040 var newAllocationRatio AuctionEventNewAllocationRatio
1041 if err := c.contractAbi.Unpack(&newAllocationRatio, "NewAllocationRatio", vLog.Data); err != nil {
1042 return nil, nil, err
1043 }
1044 auctionEvents.NewAllocationRatio = append(auctionEvents.NewAllocationRatio, newAllocationRatio)
1045 case logNewCoordinator:
1046 var newCoordinator AuctionEventNewCoordinator
1047 if err := c.contractAbi.Unpack(&newCoordinator, "NewCoordinator", vLog.Data); err != nil {
1048 return nil, nil, err
1049 }
1050 auctionEvents.NewCoordinator = append(auctionEvents.NewCoordinator, newCoordinator)
1051 case logCoordinatorUpdated:
1052 var coordinatorUpdated AuctionEventCoordinatorUpdated
1053 if err := c.contractAbi.Unpack(&coordinatorUpdated, "CoordinatorUpdated", vLog.Data); err != nil {
1054 return nil, nil, err
1055 }
1056 auctionEvents.CoordinatorUpdated = append(auctionEvents.CoordinatorUpdated, coordinatorUpdated)
1057 case logNewForgeAllocated:
1058 var newForgeAllocated AuctionEventNewForgeAllocated
1059 if err := c.contractAbi.Unpack(&newForgeAllocated, "NewForgeAllocated", vLog.Data); err != nil {
1060 return nil, nil, err
1061 }
1062 newForgeAllocated.Forger = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
1063 newForgeAllocated.CurrentSlot = new(big.Int).SetBytes(vLog.Topics[2][:]).Int64()
1064 auctionEvents.NewForgeAllocated = append(auctionEvents.NewForgeAllocated, newForgeAllocated)
1065 case logNewDefaultSlotSetBid:
1066 var auxNewDefaultSlotSetBid struct {
1067 SlotSet *big.Int
1068 NewInitialMinBid *big.Int
1069 }
1070 var newDefaultSlotSetBid AuctionEventNewDefaultSlotSetBid
1071 if err := c.contractAbi.Unpack(&auxNewDefaultSlotSetBid, "NewDefaultSlotSetBid", vLog.Data); err != nil {
1072 return nil, nil, err
1073 }
1074 newDefaultSlotSetBid.NewInitialMinBid = auxNewDefaultSlotSetBid.NewInitialMinBid
1075 newDefaultSlotSetBid.SlotSet = auxNewDefaultSlotSetBid.SlotSet.Int64()
1076 auctionEvents.NewDefaultSlotSetBid = append(auctionEvents.NewDefaultSlotSetBid, newDefaultSlotSetBid)
1077 case logNewForge:
1078 var newForge AuctionEventNewForge
1079 newForge.Forger = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
1080 newForge.CurrentSlot = new(big.Int).SetBytes(vLog.Topics[2][:]).Int64()
1081 auctionEvents.NewForge = append(auctionEvents.NewForge, newForge)
1082 case logHEZClaimed:
1083 var HEZClaimed AuctionEventHEZClaimed
1084 if err := c.contractAbi.Unpack(&HEZClaimed, "HEZClaimed", vLog.Data); err != nil {
1085 return nil, nil, err
1086 }
1087 HEZClaimed.Owner = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
1088 auctionEvents.HEZClaimed = append(auctionEvents.HEZClaimed, HEZClaimed)
1089 }
1090 }
1091 return &auctionEvents, &blockHash, nil
1092}