Skip to content

Commit

Permalink
feat: account event for Core and Account contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
asolovov committed May 17, 2024
1 parent 02cdd95 commit e52d80b
Show file tree
Hide file tree
Showing 9 changed files with 357 additions and 3 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ generate-erc7412-mainnet-c:
go run ./utils/getAbis/get-abis.go --get-mkdir ./cannon-synthetix/base/pyth_erc7412_wrapper/PythERC7412Wrapper.json ./contracts/ERC7412
abigen --abi=./contracts/PythERC7412Wrapper.json --pkg=ERC7412 --out=./contracts/ERC7412/contract.go

generate-account-mainnet-c:
go run ./utils/getAbis/get-abis.go --get-mkdir ./cannon-synthetix/base/system/AccountProxy.json ./contracts/Account
abigen --abi=./contracts/AccountProxy.json --pkg=Account --out=./contracts/Account/contract.go


# update Synthetix-Gitbook-v3 subtree
update-subtree:
git subtree pull --prefix Synthetix-Gitbook-v3 git@github.com:Synthetixio/Synthetix-Gitbook-v3.git en --squash
Expand Down
4 changes: 4 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ type ContractAddresses struct {
PerpsMarket string
ERC7412 string
Forwarder string
Account string
}

// FirstContractBlocks is a part of a config struct with default first block numbers used to filters contract logs
type FirstContractBlocks struct {
Core uint64
PerpsMarket uint64
Account uint64
}

// GetOptimismGoerliDefaultConfig is used to get default lib config for goerli optimism test net
Expand Down Expand Up @@ -130,10 +132,12 @@ func GetBaseMainnetDefaultConfig(rpcURL string) *PerpsvConfig {
PerpsMarket: "0x0A2AF931eFFd34b81ebcc57E3d3c9B1E1dE1C9Ce",
Forwarder: "0xE2C5658cC5C448B48141168f3e475dF8f65A1e3e",
ERC7412: "0xEb38e347F24ea04ffA945a475BdD949E0c383A0F",
Account: "0x63f4Dd0434BEB5baeCD27F3778a909278d8cf5b8",
},
FirstContractBlocks: &FirstContractBlocks{
Core: 7889212,
PerpsMarket: 7889389,
Account: 8394165,
},
ConnectionTimeout: time.Second * 30,
ReadTimeout: time.Second * 15,
Expand Down
4 changes: 2 additions & 2 deletions contracts/core/contract.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

87 changes: 87 additions & 0 deletions events/accountPermissionRevokedCore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package events

import (
"strings"

"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"
)

// AccountCorePermissionRevokedSubscription is a struct for listening to all 'PermissionRevoked' contract events and return them as models.PermissionChanged struct
type AccountCorePermissionRevokedSubscription struct {
*basicSubscription
PermissionChangeChan chan *models.PermissionChanged
contractEventChan chan *core.CorePermissionRevoked
}

func (e *Events) ListenAccountCorePermissionRevoked() (*AccountCorePermissionRevokedSubscription, error) {
revokedChan := make(chan *core.CorePermissionRevoked)

revokedSub, err := e.core.WatchPermissionRevoked(nil, revokedChan, nil, nil, nil)
if err != nil {
logger.Log().WithField("layer", "Events-AccountCorePermissionRevoked").Errorf("error watch permission revoked: %v", err.Error())
return nil, errors.GetEventListenErr(err, "AccountCorePermissionRevoked")
}

accountsSub := newAccountCorePermissionRevokedSubscription(revokedSub, revokedChan)

go accountsSub.listen(e.core)

return accountsSub, nil
}

// newAccountCorePermissionRevokedSubscription is used to get new AccountCorePermissionRevokedSubscription instance
func newAccountCorePermissionRevokedSubscription(
eventSub event.Subscription,
revoked chan *core.CorePermissionRevoked,
) *AccountCorePermissionRevokedSubscription {
return &AccountCorePermissionRevokedSubscription{
basicSubscription: newBasicSubscription(eventSub),
PermissionChangeChan: make(chan *models.PermissionChanged),
contractEventChan: revoked,
}
}

// listen is used to run events listen goroutine
func (s *AccountCorePermissionRevokedSubscription) listen(perps *core.Core) {
defer func() {
close(s.PermissionChangeChan)
close(s.contractEventChan)
}()

for {
select {
case <-s.stop:
return
case err := <-s.eventSub.Err():
if err != nil {
logger.Log().WithField("layer", "Events-AccountCorePermissionRevoked").Errorf(
"error listening account permission revoked: %v", err.Error(),
)
s.ErrChan <- err
}
return
case contractEvent := <-s.contractEventChan:
p, err := models.PermissionFromString(strings.TrimRight(string(contractEvent.Permission[:]), string(rune(0))))
if err != nil {
logger.Log().WithField("layer", "Events-AccountCorePermissionRevoked").Errorf(
"error decode permission %v: %v", string(contractEvent.Permission[:]), err.Error(),
)
s.ErrChan <- err
continue
}

change := &models.PermissionChanged{
AccountID: contractEvent.AccountId,
User: contractEvent.User,
Permission: p,
}

s.PermissionChangeChan <- change
}
}
}
87 changes: 87 additions & 0 deletions events/accountPermissionsGrantedCore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package events

import (
"strings"

"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"
)

// AccountCorePermissionGrantedSubscription is a struct for listening to all 'PermissionGranted' contract events and return them as models.PermissionChanged struct
type AccountCorePermissionGrantedSubscription struct {
*basicSubscription
PermissionChangeChan chan *models.PermissionChanged
contractEventChan chan *core.CorePermissionGranted
}

func (e *Events) ListenAccountCorePermissionGranted() (*AccountCorePermissionGrantedSubscription, error) {
createdChan := make(chan *core.CorePermissionGranted)

createdSub, err := e.core.WatchPermissionGranted(nil, createdChan, nil, nil, nil)
if err != nil {
logger.Log().WithField("layer", "Events-AccountCorePermissionGranted").Errorf("error watch permission granted: %v", err.Error())
return nil, errors.GetEventListenErr(err, "AccountCorePermissionGranted")
}

accountsSub := newAccountCorePermissionGrantedSubscription(createdSub, createdChan)

go accountsSub.listen(e.core)

return accountsSub, nil
}

// newAccountCorePermissionGrantedSubscription is used to get new AccountCorePermissionGrantedSubscription instance
func newAccountCorePermissionGrantedSubscription(
eventSub event.Subscription,
created chan *core.CorePermissionGranted,
) *AccountCorePermissionGrantedSubscription {
return &AccountCorePermissionGrantedSubscription{
basicSubscription: newBasicSubscription(eventSub),
PermissionChangeChan: make(chan *models.PermissionChanged),
contractEventChan: created,
}
}

// listen is used to run events listen goroutine
func (s *AccountCorePermissionGrantedSubscription) listen(perps *core.Core) {
defer func() {
close(s.PermissionChangeChan)
close(s.contractEventChan)
}()

for {
select {
case <-s.stop:
return
case err := <-s.eventSub.Err():
if err != nil {
logger.Log().WithField("layer", "Events-AccountCorePermissionGranted").Errorf(
"error listening account permission granted: %v", err.Error(),
)
s.ErrChan <- err
}
return
case contractEvent := <-s.contractEventChan:
p, err := models.PermissionFromString(strings.TrimRight(string(contractEvent.Permission[:]), string(rune(0))))
if err != nil {
logger.Log().WithField("layer", "Events-AccountCorePermissionGranted").Errorf(
"error decode permission %v: %v", string(contractEvent.Permission[:]), err.Error(),
)
s.ErrChan <- err
continue
}

change := &models.PermissionChanged{
AccountID: contractEvent.AccountId,
User: contractEvent.User,
Permission: p,
}

s.PermissionChangeChan <- change
}
}
}
84 changes: 84 additions & 0 deletions events/accountTransfer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package events

import (
"context"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/event"
"github.com/gateway-fm/perpsv3-Go/contracts/Account"
"github.com/gateway-fm/perpsv3-Go/errors"
"github.com/gateway-fm/perpsv3-Go/models"
"github.com/gateway-fm/perpsv3-Go/pkg/logger"
"math/big"
)

// AccountTransferSubscription is a struct for listening to all 'AccountTransfer' contract events and return them as models.AccountTransfer struct
type AccountTransferSubscription struct {
*basicSubscription
NewAccountChan chan *models.AccountTransfer
contractEventChan chan *Account.AccountTransfer
}

func (e *Events) ListenAccountTransfer() (*AccountTransferSubscription, error) {
transferChan := make(chan *Account.AccountTransfer)

transferSub, err := e.account.WatchTransfer(nil, transferChan, nil, nil, nil)
if err != nil {
logger.Log().WithField("layer", "Events-Accounts").Errorf("error watch account transfer: %v", err.Error())
return nil, errors.GetEventListenErr(err, "AccountTransfer")
}

accountsSub := newAccountTransferSubscription(transferSub, transferChan)

go accountsSub.listen(e.rpcClient)

return accountsSub, nil
}

// newAccountTransferSubscription is used to get new AccountTransferSubscription instance
func newAccountTransferSubscription(
eventSub event.Subscription,
transfer chan *Account.AccountTransfer,
) *AccountTransferSubscription {
return &AccountTransferSubscription{
basicSubscription: newBasicSubscription(eventSub),
NewAccountChan: make(chan *models.AccountTransfer),
contractEventChan: transfer,
}
}

// listen is used to run events listen goroutine
func (s *AccountTransferSubscription) 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-AccountTransfer").Errorf(
"error listening account transfer info: %v", err.Error(),
)
s.ErrChan <- err
}
return
case transfer := <-s.contractEventChan:
block, err := rpcClient.HeaderByNumber(context.Background(), big.NewInt(int64(transfer.Raw.BlockNumber)))
time := uint64(0)
if err != nil {
logger.Log().WithField("layer", "Events-AccountTransfer").Warningf(
"error fetching block number %v: %v; transfer event time set to 0 ",
transfer.Raw.BlockNumber, err.Error(),
)
s.ErrChan <- err
} else {
time = block.Time
}

s.NewAccountChan <- models.GetAccountTransferFromEvent(transfer, time)
}
}
}
16 changes: 16 additions & 0 deletions events/events.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package events

import (
"github.com/gateway-fm/perpsv3-Go/contracts/Account"
"math/big"

"github.com/ethereum/go-ethereum/ethclient"
Expand Down Expand Up @@ -104,25 +105,40 @@ type IEvents interface {
// 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)

// ListenAccountTransfer is used to listen to all 'Transfer' Account contract events and return them as models.AccountTransfer
// struct and return errors on ErrChan chanel
ListenAccountTransfer() (*AccountTransferSubscription, error)

// ListenAccountCorePermissionRevoked is used to listen to all 'PermissionRevoked' Core contract events and return them as models.PermissionChanged
// struct and return errors on ErrChan chanel
ListenAccountCorePermissionRevoked() (*AccountCorePermissionRevokedSubscription, error)

// ListenAccountCorePermissionGranted is used to listen to all 'PermissionGranted' Core contract events and return them as models.PermissionChanged
// struct and return errors on ErrChan chanel
ListenAccountCorePermissionGranted() (*AccountCorePermissionGrantedSubscription, error)
}

// Events implements IEvents interface
type Events struct {
rpcClient *ethclient.Client
core *core.Core
perpsMarket *perpsMarket.PerpsMarket
account *Account.Account
}

// NewEvents is used to create new Events instance that implements IEvents interface
func NewEvents(
client *ethclient.Client,
core *core.Core,
perpsMarket *perpsMarket.PerpsMarket,
account *Account.Account,
) IEvents {
return &Events{
rpcClient: client,
core: core,
perpsMarket: perpsMarket,
account: account,
}
}

Expand Down
Loading

0 comments on commit e52d80b

Please sign in to comment.