Skip to content

Commit

Permalink
Merge pull request #24 from indexed-finance/refactor
Browse files Browse the repository at this point in the history
Codebase Refactor & Simplification
  • Loading branch information
bonedaddy authored Mar 28, 2021
2 parents d289f3f + dddfdc4 commit ec4d2b8
Show file tree
Hide file tree
Showing 19 changed files with 962 additions and 316 deletions.
23 changes: 3 additions & 20 deletions alerts/alerts_test.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,17 @@
package alerts

import (
"os"
"testing"

"github.com/indexed-finance/circuit-breaker/config"
testutils "github.com/indexed-finance/circuit-breaker/utils/tests"

"github.com/stretchr/testify/require"
"go.uber.org/zap"
)

var (
twilioSID = os.Getenv("TWILIO_SID")
twilioAuthToken = os.Getenv("TWILIO_AUTH_TOKEN")
twilioTestRecipient = os.Getenv("TWILIO_TEST_RECIPIENT")
twilioNumber = os.Getenv("TWILIO_NUMBER")
)

func getConfig(t *testing.T) *config.Config {
exCfg := *config.ExampleConfig
exCfg.InfuraAPIKey = os.Getenv("INFURA_API_KEY")
exCfg.Alerts.Twilio.Recipients = []string{twilioTestRecipient}
exCfg.Alerts.Twilio.From = twilioNumber
exCfg.Alerts.Twilio.SID = twilioSID
exCfg.Alerts.Twilio.AuthToken = twilioAuthToken
return &exCfg
}

func TestAlerter(t *testing.T) {
t.Run("Twilio", func(t *testing.T) {
cfg := getConfig(t)
cfg := testutils.GetConfig(t)
logger, err := zap.NewDevelopment()
require.NoError(t, err)
alerter := New(logger, cfg.Alerts)
Expand Down
58 changes: 58 additions & 0 deletions circuit/circuit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package circuit

import (
"context"
"math/big"

dutils "github.com/bonedaddy/go-defi/utils"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/indexed-finance/circuit-breaker/bindings/controller"
"github.com/indexed-finance/circuit-breaker/utils"
"go.uber.org/zap"
)

// BreakConfig provides a configuration to use for breaking circuits
type BreakConfig struct {
Ctx context.Context
BC dutils.Blockchain
MinimumGwei *big.Int
GasMultiplier *big.Int
Auth *utils.Authorizer
PoolAddress common.Address
PoolName string
Logger *zap.Logger
Breaker *controller.Controller
}

func BreakCircuit(cfg BreakConfig) error {
gasPrice, err := utils.GetGasPrice(cfg.Ctx, cfg.BC, cfg.MinimumGwei, cfg.GasMultiplier)
if err != nil {
cfg.Logger.Error("failed to suggest gas price", zap.Error(err))
return err
}
cfg.Logger.Info("gas price calculated (includes boost)", zap.String("gas.price", gasPrice.String()))
cfg.Auth.Lock()
cfg.Auth.GasPrice = gasPrice
tx, err := cfg.Breaker.SetPublicSwap(cfg.Auth.TransactOpts, cfg.PoolAddress, false)
cfg.Auth.GasPrice = nil
cfg.Auth.Unlock()
if err != nil {
cfg.Logger.Error("failed to broadcast public swap disable tx", zap.Error(err))
return err
}
cfg.Logger.Warn(
"public swap disable transaction sent",
zap.String("tx.hash", tx.Hash().String()),
zap.String("pool", cfg.PoolName),
)
rcpt, err := bind.WaitMined(cfg.Ctx, cfg.BC, tx)
if err != nil {
cfg.Logger.Error("failed to wait for transaction to be mined", zap.Error(err), zap.String("pool", cfg.PoolName), zap.String("tx.hash", tx.Hash().String()))
return err
}
if rcpt.Status != 1 {
cfg.Logger.Warn("public swap tx failed to execute correctly as status code is not 1", zap.String("pool", cfg.PoolName), zap.String("tx.hash", tx.Hash().String()))
}
return nil
}
47 changes: 47 additions & 0 deletions circuit/circuit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package circuit

import (
"context"
"math/big"
"testing"
"time"

"github.com/bonedaddy/go-defi/testenv"
"github.com/indexed-finance/circuit-breaker/bindings/controller"
"github.com/indexed-finance/circuit-breaker/bindings/logswap"
"github.com/indexed-finance/circuit-breaker/utils"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
)

func TestBreakCircuit(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
tenv, err := testenv.NewBlockchain(ctx)
require.NoError(t, err)
authorizer := utils.NewAuthorizerFromPK(tenv.PK())
//cfg := testutils.GetConfig(t)
addr, tx, _, err := logswap.DeployLogswap(tenv.Auth, tenv)
require.NoError(t, err)
_, err = tenv.DoWaitDeployed(tx)
require.NoError(t, err)
breaker, err := controller.NewController(addr, tenv)
require.NoError(t, err)
go func() {
time.Sleep(time.Second * 5)
tenv.Commit()
}()
require.NoError(t, BreakCircuit(
BreakConfig{
Ctx: ctx,
BC: tenv,
MinimumGwei: big.NewInt(1000),
GasMultiplier: big.NewInt(3),
Auth: authorizer,
PoolAddress: addr,
PoolName: "yodawg",
Logger: zap.NewNop(),
Breaker: breaker,
},
))
}
23 changes: 6 additions & 17 deletions eventwatcher/event_watacher_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package eventwatcher

import (
"os"
"context"
"testing"

"github.com/bonedaddy/go-indexed/bclient"
"github.com/bonedaddy/go-defi/testenv"
"github.com/stretchr/testify/require"
)

Expand All @@ -15,21 +15,10 @@ var (
}
)

func doSetup(t *testing.T) *EventWatcher {
infuraAPIKey := os.Getenv("INFURA_API_KEY")
if infuraAPIKey == "" {
t.Fatal("INFURA_API_KEY env var is empty")
}
client, err := bclient.NewInfuraClient(infuraAPIKey, true)
require.NoError(t, err)
return New(client)
}

func TestEventWatcher(t *testing.T) {
client := doSetup(t)
t.Cleanup(func() {
client.Close()
})
_, err := client.NewBindings(pools)
tenv, err := testenv.NewBlockchain(context.Background())
require.NoError(t, err)
client := New(tenv)
_, err = client.NewBindings(pools)
require.NoError(t, err)
}
16 changes: 10 additions & 6 deletions eventwatcher/event_watcher.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
package eventwatcher

import (
"github.com/bonedaddy/go-indexed/bclient"
"github.com/bonedaddy/go-defi/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/indexed-finance/circuit-breaker/bindings/sigmacore"
)

// EventWatcher wraps one or more interfaces to the ethereum blockchain to watch events
type EventWatcher struct {
bc *bclient.Client
bc utils.Blockchain
// bc *bclient.Client
// TODO(bonedaddy): add highly available lookups
}

// New returns a new EventWatcher implementation
func New(bc *bclient.Client) *EventWatcher {
func New(bc utils.Blockchain) *EventWatcher {
return &EventWatcher{bc: bc}
}

// NewBindings constructs poolbindings for various indices, the input addresses argument is a map of pool name -> pool address
func (ew *EventWatcher) NewBindings(addresses map[string]string) (map[string]*sigmacore.Sigmacore, error) {
out := make(map[string]*sigmacore.Sigmacore)
for name, addr := range addresses {
binding, err := sigmacore.NewSigmacore(common.HexToAddress(addr), ew.bc.EthClient())
binding, err := sigmacore.NewSigmacore(common.HexToAddress(addr), ew.bc)
if err != nil {
return nil, err
}
Expand All @@ -31,12 +33,14 @@ func (ew *EventWatcher) NewBindings(addresses map[string]string) (map[string]*si
}

// BC returns the underlying blockchain client
func (ew *EventWatcher) BC() *bclient.Client {
func (ew *EventWatcher) BC() utils.Blockchain {
return ew.bc
}

// Close is used to terminate the event watcher
func (ew *EventWatcher) Close() error {
ew.bc.Close()
if ibc, ok := ew.bc.(*ethclient.Client); ok {
ibc.Close()
}
return nil
}
46 changes: 30 additions & 16 deletions eventwatcher/handle_log_swaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"math"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/indexed-finance/circuit-breaker/alerts"
"github.com/indexed-finance/circuit-breaker/circuit"
"github.com/indexed-finance/circuit-breaker/database"
"github.com/indexed-finance/circuit-breaker/utils"
"go.uber.org/zap"
Expand All @@ -19,7 +19,6 @@ func (wc *WatchedContract) handleLogSwaps(
alerter *alerts.Alerter,
authorizer *utils.Authorizer,
breakPercentage float64,
ec *ethclient.Client,
poolAddress common.Address,
) error {
defer func() {
Expand Down Expand Up @@ -112,21 +111,36 @@ func (wc *WatchedContract) handleLogSwaps(
zap.Float64("break.percentage", breakPercentage),
)

// lock the authorizer since bind.TransactOpts is not threadsafe
authorizer.Lock()

gasPrice, err := utils.GetGasPrice(ctx, wc.backend, wc.minimumGwei, wc.gasMultiplier)
if err != nil {
wc.logger.Error("failed to suggest gasprice", zap.Error(err))
} else {
wc.logger.Info("gas price calculated (includes boost)", zap.String("gas.price", gasPrice.String()))
wc.setPublicSwap(ctx, authorizer, poolAddress, gasPrice, wc.name, ec)
// check to see if an anctive circuit break is ongoing
wc.breakLock.Lock()
if wc.breaking {
wc.logger.Warn("attempting to trigger circuit break while one is ongoing")
wc.breakLock.Unlock()
continue
}

// we need to unset the gas price that we overrode the transactor with
// so that future uses of this transactor have the gas price set to nil
authorizer.TransactOpts.GasPrice = nil
authorizer.Unlock()
wc.breaking = true
wc.breakLock.Unlock()
if err := circuit.BreakCircuit(circuit.BreakConfig{
Ctx: ctx,
BC: wc.bc,
MinimumGwei: wc.minimumGwei,
GasMultiplier: wc.gasMultiplier,
Auth: authorizer,
PoolAddress: poolAddress,
PoolName: wc.name,
Logger: wc.logger,
Breaker: wc.breaker,
}); err != nil {
wc.logger.Error(
"circuit break failed to execute properly",
zap.Error(err),
zap.String("pool", wc.name),
)
}
// unset the breaking boolean
wc.breakLock.Lock()
wc.breaking = false
wc.breakLock.Unlock()

if err := alerter.NotifyCircuitBreak(
fmt.Sprintf(
Expand Down
42 changes: 0 additions & 42 deletions eventwatcher/types.go

This file was deleted.

Loading

0 comments on commit ec4d2b8

Please sign in to comment.