From b170aa5b8d98290f1cc7ba41f27f4d093f95d026 Mon Sep 17 00:00:00 2001 From: asolovov Date: Fri, 3 May 2024 11:50:52 +0300 Subject: [PATCH] feat: core liquidation listeners --- contracts/core/contract.go | 4 +- events/events.go | 8 +++ events/liauidationsCore.go | 86 +++++++++++++++++++++++++++++++++ events/vaultLiquidationsCore.go | 86 +++++++++++++++++++++++++++++++++ perpsv3.go | 16 ++++++ 5 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 events/liauidationsCore.go create mode 100644 events/vaultLiquidationsCore.go diff --git a/contracts/core/contract.go b/contracts/core/contract.go index b0fd634..a76e963 100644 --- a/contracts/core/contract.go +++ b/contracts/core/contract.go @@ -5840,7 +5840,7 @@ func (_Core *CoreFilterer) WatchLiquidation(opts *bind.WatchOpts, sink chan<- *C collateralTypeRule = append(collateralTypeRule, collateralTypeItem) } - logs, sub, err := _Core.contract.WatchLogs(opts, "Liquidation", accountIdRule, poolIdRule, collateralTypeRule) + logs, sub, err := _Core.contract.WatchLogs(opts, "Liquidation") if err != nil { return nil, err } @@ -11504,7 +11504,7 @@ func (_Core *CoreFilterer) WatchVaultLiquidation(opts *bind.WatchOpts, sink chan collateralTypeRule = append(collateralTypeRule, collateralTypeItem) } - logs, sub, err := _Core.contract.WatchLogs(opts, "VaultLiquidation", poolIdRule, collateralTypeRule) + logs, sub, err := _Core.contract.WatchLogs(opts, "VaultLiquidation") if err != nil { return nil, err } diff --git a/events/events.go b/events/events.go index db0411d..db2dc4e 100644 --- a/events/events.go +++ b/events/events.go @@ -92,6 +92,14 @@ type IEvents interface { // ListenPoolCreated is used to listen to all 'PoolCreated' Core contract events and return them as models.PoolCreated // struct and return errors on ErrChan chanel ListenPoolCreated() (*PoolCreatedSubscription, error) + + // ListenVaultLiquidationsCore is used to listen to all 'VaultLiquidations' Core contract events and return them as models.CoreVaultLiquidation + // struct and return errors on ErrChan chanel + ListenVaultLiquidationsCore() (*VaultLiquidationsCoreSubscription, error) + + // ListenLiquidationsCore is used to listen to all 'Liquidations' Core contract events and return them as models.CoreLiquidation + // struct and return errors on ErrChan chanel + ListenLiquidationsCore() (*LiquidationsCoreSubscription, error) } // Events implements IEvents interface diff --git a/events/liauidationsCore.go b/events/liauidationsCore.go new file mode 100644 index 0000000..13157c0 --- /dev/null +++ b/events/liauidationsCore.go @@ -0,0 +1,86 @@ +package events + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/event" + + "github.com/gateway-fm/perpsv3-Go/contracts/core" + "github.com/gateway-fm/perpsv3-Go/errors" + "github.com/gateway-fm/perpsv3-Go/models" + "github.com/gateway-fm/perpsv3-Go/pkg/logger" +) + +// LiquidationsCoreSubscription is a struct for listening to all 'LiquidationsCore' contract events and return them as models.Account struct +type LiquidationsCoreSubscription struct { + *basicSubscription + NewAccountChan chan *models.CoreLiquidation + contractEventChan chan *core.CoreLiquidation +} + +func (e *Events) ListenLiquidationsCore() (*LiquidationsCoreSubscription, error) { + liquidationChan := make(chan *core.CoreLiquidation) + + liquidationSub, err := e.core.WatchLiquidation(nil, liquidationChan, nil, nil, nil) + if err != nil { + logger.Log().WithField("layer", "Events-LiquidationsCore").Errorf("error watch liquidation: %v", err.Error()) + return nil, errors.GetEventListenErr(err, "LiquidationsCore") + } + + liquidationsSub := newLiquidationsCoreSubscription(liquidationSub, liquidationChan) + + go liquidationsSub.listen(e.rpcClient) + + return liquidationsSub, nil +} + +// newLiquidationsCoreSubscription is used to get new LiquidationsCoreSubscription instance +func newLiquidationsCoreSubscription( + eventSub event.Subscription, + liquidation chan *core.CoreLiquidation, +) *LiquidationsCoreSubscription { + return &LiquidationsCoreSubscription{ + basicSubscription: newBasicSubscription(eventSub), + NewAccountChan: make(chan *models.CoreLiquidation), + contractEventChan: liquidation, + } +} + +// listen is used to run events listen goroutine +func (s *LiquidationsCoreSubscription) listen(rpcClient *ethclient.Client) { + defer func() { + close(s.NewAccountChan) + close(s.contractEventChan) + }() + + for { + select { + case <-s.stop: + return + case err := <-s.eventSub.Err(): + if err != nil { + logger.Log().WithField("layer", "Events-LiquidationsCore").Errorf( + "error listening liquidation info: %v", err.Error(), + ) + s.ErrChan <- err + } + return + case liquidation := <-s.contractEventChan: + block, err := rpcClient.HeaderByNumber(context.Background(), big.NewInt(int64(liquidation.Raw.BlockNumber))) + time := uint64(0) + if err != nil { + logger.Log().WithField("layer", "Events-LiquidationsCore").Warningf( + "error fetching block number %v: %v; liquidation event time set to 0 ", + liquidation.Raw.BlockNumber, err.Error(), + ) + s.ErrChan <- err + } else { + time = block.Time + } + + s.NewAccountChan <- models.GetCoreLiquidationFromEvent(liquidation, time) + } + } +} diff --git a/events/vaultLiquidationsCore.go b/events/vaultLiquidationsCore.go new file mode 100644 index 0000000..fdbaeb4 --- /dev/null +++ b/events/vaultLiquidationsCore.go @@ -0,0 +1,86 @@ +package events + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/event" + + "github.com/gateway-fm/perpsv3-Go/contracts/core" + "github.com/gateway-fm/perpsv3-Go/errors" + "github.com/gateway-fm/perpsv3-Go/models" + "github.com/gateway-fm/perpsv3-Go/pkg/logger" +) + +// VaultLiquidationsCoreSubscription is a struct for listening to all 'VaultLiquidationsCore' contract events and return them as models.Account struct +type VaultLiquidationsCoreSubscription struct { + *basicSubscription + NewAccountChan chan *models.CoreVaultLiquidation + contractEventChan chan *core.CoreVaultLiquidation +} + +func (e *Events) ListenVaultLiquidationsCore() (*VaultLiquidationsCoreSubscription, error) { + liquidationChan := make(chan *core.CoreVaultLiquidation) + + liquidationSub, err := e.core.WatchVaultLiquidation(nil, liquidationChan, nil, nil) + if err != nil { + logger.Log().WithField("layer", "Events-VaultLiquidationsCore").Errorf("error watch liquidation: %v", err.Error()) + return nil, errors.GetEventListenErr(err, "VaultLiquidationsCore") + } + + liquidationsSub := newVaultLiquidationsCoreSubscription(liquidationSub, liquidationChan) + + go liquidationsSub.listen(e.rpcClient) + + return liquidationsSub, nil +} + +// newVaultLiquidationsCoreSubscription is used to get new VaultLiquidationsCoreSubscription instance +func newVaultLiquidationsCoreSubscription( + eventSub event.Subscription, + liquidation chan *core.CoreVaultLiquidation, +) *VaultLiquidationsCoreSubscription { + return &VaultLiquidationsCoreSubscription{ + basicSubscription: newBasicSubscription(eventSub), + NewAccountChan: make(chan *models.CoreVaultLiquidation), + contractEventChan: liquidation, + } +} + +// listen is used to run events listen goroutine +func (s *VaultLiquidationsCoreSubscription) listen(rpcClient *ethclient.Client) { + defer func() { + close(s.NewAccountChan) + close(s.contractEventChan) + }() + + for { + select { + case <-s.stop: + return + case err := <-s.eventSub.Err(): + if err != nil { + logger.Log().WithField("layer", "Events-VaultLiquidationsCore").Errorf( + "error listening liquidation info: %v", err.Error(), + ) + s.ErrChan <- err + } + return + case liquidation := <-s.contractEventChan: + block, err := rpcClient.HeaderByNumber(context.Background(), big.NewInt(int64(liquidation.Raw.BlockNumber))) + time := uint64(0) + if err != nil { + logger.Log().WithField("layer", "Events-VaultLiquidationsCore").Warningf( + "error fetching block number %v: %v; liquidation event time set to 0 ", + liquidation.Raw.BlockNumber, err.Error(), + ) + s.ErrChan <- err + } else { + time = block.Time + } + + s.NewAccountChan <- models.GetCoreVaultLiquidationFromEvent(liquidation, time) + } + } +} diff --git a/perpsv3.go b/perpsv3.go index 08ca22a..c68f16d 100644 --- a/perpsv3.go +++ b/perpsv3.go @@ -209,6 +209,14 @@ type IPerpsv3 interface { // struct and return errors on ErrChan chanel ListenPoolCreated() (*events.PoolCreatedSubscription, error) + // ListenVaultLiquidationsCore is used to listen to all 'VaultLiquidations' Core contract events and return them as models.CoreVaultLiquidation + // struct and return errors on ErrChan chanel + ListenVaultLiquidationsCore() (*events.VaultLiquidationsCoreSubscription, error) + + // ListenLiquidationsCore is used to listen to all 'Liquidations' Core contract events and return them as models.CoreLiquidation + // struct and return errors on ErrChan chanel + ListenLiquidationsCore() (*events.LiquidationsCoreSubscription, error) + // GetPosition is used to get position data struct from latest block with given params // Function can return contract error if market ID is invalid GetPosition(accountID *big.Int, marketID *big.Int) (*models.Position, error) @@ -511,6 +519,14 @@ func (p *Perpsv3) ListenPoolCreated() (*events.PoolCreatedSubscription, error) { return p.events.ListenPoolCreated() } +func (p *Perpsv3) ListenVaultLiquidationsCore() (*events.VaultLiquidationsCoreSubscription, error) { + return p.events.ListenVaultLiquidationsCore() +} + +func (p *Perpsv3) ListenLiquidationsCore() (*events.LiquidationsCoreSubscription, error) { + return p.events.ListenLiquidationsCore() +} + func (p *Perpsv3) GetPosition(accountID *big.Int, marketID *big.Int) (*models.Position, error) { return p.service.GetPosition(accountID, marketID) }