Skip to content

Commit

Permalink
Merge 7a71c2d into 9916a14
Browse files Browse the repository at this point in the history
  • Loading branch information
trajan0x authored Jul 5, 2024
2 parents 9916a14 + 7a71c2d commit b74114a
Show file tree
Hide file tree
Showing 57 changed files with 962 additions and 84 deletions.
2 changes: 1 addition & 1 deletion agents/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ require (
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.4 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/hashicorp/consul/sdk v0.14.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
Expand Down
3 changes: 1 addition & 2 deletions agents/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -622,8 +622,7 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8=
github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls=
github.com/grafana/pyroscope-go v1.1.1 h1:PQoUU9oWtO3ve/fgIiklYuGilvsm8qaGhlY4Vw6MAcQ=
Expand Down
48 changes: 44 additions & 4 deletions contrib/opbot/botmd/botmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@ package botmd

import (
"context"
"fmt"
"github.com/slack-io/slacker"
"github.com/synapsecns/sanguine/contrib/opbot/config"
"github.com/synapsecns/sanguine/contrib/opbot/signoz"
"github.com/synapsecns/sanguine/core/dbcommon"
"github.com/synapsecns/sanguine/core/metrics"
signerConfig "github.com/synapsecns/sanguine/ethergo/signer/config"
"github.com/synapsecns/sanguine/ethergo/signer/signer"
"github.com/synapsecns/sanguine/ethergo/submitter"
cctpSql "github.com/synapsecns/sanguine/services/cctp-relayer/db/sql"
omnirpcClient "github.com/synapsecns/sanguine/services/omnirpc/client"
"golang.org/x/sync/errgroup"
)

// Bot represents the bot server.
Expand All @@ -15,10 +23,13 @@ type Bot struct {
cfg config.Config
signozClient *signoz.Client
signozEnabled bool
rpcClient omnirpcClient.RPCClient
signer signer.Signer
submitter submitter.TransactionSubmitter
}

// NewBot creates a new bot server.
func NewBot(handler metrics.Handler, cfg config.Config) Bot {
func NewBot(handler metrics.Handler, cfg config.Config) *Bot {
server := slacker.NewClient(cfg.SlackBotToken, cfg.SlackAppToken)
bot := Bot{
handler: handler,
Expand All @@ -32,10 +43,12 @@ func NewBot(handler metrics.Handler, cfg config.Config) Bot {
bot.signozEnabled = true
}

bot.rpcClient = omnirpcClient.NewOmnirpcClient(cfg.OmniRPCURL, handler, omnirpcClient.WithCaptureReqRes())

bot.addMiddleware(bot.tracingMiddleware(), bot.metricsMiddleware())
bot.addCommands(bot.traceCommand(), bot.rfqLookupCommand())
bot.addCommands(bot.traceCommand(), bot.rfqLookupCommand(), bot.rfqRefund())

return bot
return &bot
}

func (b *Bot) addMiddleware(middlewares ...slacker.CommandMiddlewareHandler) {
Expand All @@ -53,6 +66,33 @@ func (b *Bot) addCommands(commands ...*slacker.CommandDefinition) {
// Start starts the bot server.
// nolint: wrapcheck
func (b *Bot) Start(ctx context.Context) error {
var err error
b.signer, err = signerConfig.SignerFromConfig(ctx, b.cfg.Signer)
if err != nil {
return fmt.Errorf("failed to create signer: %w", err)
}

dbType, err := dbcommon.DBTypeFromString(b.cfg.Database.Type)
if err != nil {
return fmt.Errorf("could not get db type: %w", err)
}

store, err := cctpSql.Connect(ctx, dbType, b.cfg.Database.DSN, b.handler)
if err != nil {
return fmt.Errorf("could not connect to database: %w", err)
}

b.submitter = submitter.NewTransactionSubmitter(b.handler, b.signer, b.rpcClient, store.SubmitterDB(), &b.cfg.SubmitterConfig)

g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
return b.submitter.Start(ctx)
})

g.Go(func() error {
return b.server.Listen(ctx)
})

// nolint: wrapcheck
return b.server.Listen(ctx)
return g.Wait()
}
135 changes: 135 additions & 0 deletions contrib/opbot/botmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,23 @@
package botmd

import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/hako/durafmt"
"github.com/slack-go/slack"
"github.com/slack-io/slacker"
"github.com/synapsecns/sanguine/contrib/opbot/signoz"
"github.com/synapsecns/sanguine/ethergo/chaindata"
rfqClient "github.com/synapsecns/sanguine/services/rfq/api/client"
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge"
"github.com/synapsecns/sanguine/services/rfq/relayer/relapi"
"log"
"math/big"
"regexp"
"strconv"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -239,6 +246,107 @@ func (b *Bot) rfqLookupCommand() *slacker.CommandDefinition {
}}
}

func (b *Bot) rfqRefund() *slacker.CommandDefinition {
return &slacker.CommandDefinition{
Command: "refund <tx> <origin_chainid>",
Description: "refund a quote request",
Examples: []string{"refund 0x1234"},
Handler: func(ctx *slacker.CommandContext) {
client, err := rfqClient.NewUnauthenticatedClient(b.handler, b.cfg.RFQApiURL)
if err != nil {
log.Printf("error creating rfq client: %v\n", err)
return
}

contracts, err := client.GetRFQContracts(ctx.Context())
if err != nil {
log.Printf("error fetching rfq contracts: %v\n", err)
_, err = ctx.Response().Reply("error fetching rfq contracts")
if err != nil {
return
}
return
}

tx := stripLinks(ctx.Request().Param("tx"))

if len(tx) == 0 {
_, err := ctx.Response().Reply("please provide a tx hash")
if err != nil {
log.Println(err)
}
return
}

originChainIDStr := ctx.Request().Param("origin_chainid")
if len(originChainIDStr) == 0 {
_, err := ctx.Response().Reply("please provide an origin chain id")
if err != nil {
log.Println(err)
}
return
}

originChainID, err := strconv.Atoi(convertChainName(originChainIDStr))
if err != nil {
_, err := ctx.Response().Reply("origin_chainid must be a number")
if err != nil {
log.Println(err)
}
return
}

chainClient, err := b.rpcClient.GetChainClient(ctx.Context(), originChainID)
if err != nil {
log.Printf("error getting chain client: %v\n", err)
return
}

contractAddress, ok := contracts.Contracts[uint32(originChainID)]
if !ok {
_, err := ctx.Response().Reply("contract address not found")
if err != nil {
log.Println(err)
}
return
}

fastBridgeHandle, err := fastbridge.NewFastBridge(common.HexToAddress(contractAddress), chainClient)
if err != nil {
log.Printf("error creating fast bridge: %v\n", err)
return
}

for _, relayer := range b.cfg.RelayerURLS {
relClient := relapi.NewRelayerClient(b.handler, relayer)

rawRequest, err := getQuoteRequest(ctx.Context(), relClient, tx)
if err != nil {
_, err := ctx.Response().Reply("error fetching quote request")
if err != nil {
log.Println(err)
}
return
}

nonce, err := b.submitter.SubmitTransaction(ctx.Context(), big.NewInt(int64(originChainID)), func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) {
return fastBridgeHandle.Refund(transactor, rawRequest)
})
if err != nil {
log.Printf("error submitting refund: %v\n", err)
continue
}

_, err = ctx.Response().Reply(fmt.Sprintf("refund submitted with nonce %d", nonce))
if err != nil {
log.Println(err)
}
return
}
},
}
}

func toExplorerSlackLink(ogHash string) string {
rfqHash := strings.ToUpper(ogHash)
// cut off 0x
Expand All @@ -264,3 +372,30 @@ func stripLinks(input string) string {
linkRegex := regexp.MustCompile(`<https?://[^|>]+\|([^>]+)>`)
return linkRegex.ReplaceAllString(input, "$1")
}

// convertChainName detects if the string contains letters and if it does, tries to convert it to a chain id.
// otherwise return the original string
func convertChainName(input string) string {
res := chaindata.ChainNameToChainID(input)
if res != 0 {
return strconv.Itoa(int(res))
}
return input
}

func getQuoteRequest(ctx context.Context, client relapi.RelayerClient, tx string) ([]byte, error) {
// at this point tx can be a txid or a has, we try both
txRequest, err := client.GetQuoteRequestStatusByTxHash(ctx, tx)
if err == nil {
// override tx with txid
tx = txRequest.TxID
}

// look up quote request
qr, err := client.GetQuoteRequestByTXID(ctx, tx)
if err != nil {
return nil, fmt.Errorf("error fetching quote request: %w", err)
}

return common.Hex2Bytes(qr.QuoteRequestRaw), nil
}
5 changes: 3 additions & 2 deletions contrib/opbot/botmd/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ const (
func (b *Bot) tracingMiddleware() slacker.CommandMiddlewareHandler {
return func(next slacker.CommandHandler) slacker.CommandHandler {
return func(cmdCtx *slacker.CommandContext) {
// TODO: context is not inherited here.
_, span := b.handler.Tracer().Start(cmdCtx.Context(), fmt.Sprintf("command.%s", cmdCtx.Definition().Command), trace.WithAttributes(
ctx, span := b.handler.Tracer().Start(cmdCtx.Context(), fmt.Sprintf("command.%s", cmdCtx.Definition().Command), trace.WithAttributes(
attribute.String("user_id", cmdCtx.Event().UserID),
attribute.String("channel_id", cmdCtx.Event().Channel.ID),
))

cmdCtx.WithContext(ctx)

defer func() {
metrics.EndSpan(span)
}()
Expand Down
3 changes: 2 additions & 1 deletion contrib/opbot/cmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"github.com/synapsecns/sanguine/contrib/opbot/botmd"
"github.com/synapsecns/sanguine/core"
"github.com/synapsecns/sanguine/core/metrics"

// used for testing.
Expand All @@ -23,7 +24,7 @@ var slackBotCommand = &cli.Command{
Usage: "start the slack bot",
Flags: []cli.Flag{fileFlag},
Action: func(c *cli.Context) error {
configFile, err := os.ReadFile(c.String(fileFlag.Name))
configFile, err := os.ReadFile(core.ExpandOrReturnPath(c.String(fileFlag.Name)))
if err != nil {
return fmt.Errorf("failed to open config file: %w", err)
}
Expand Down
21 changes: 21 additions & 0 deletions contrib/opbot/config/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// Package config provides a simple way to read and write configuration files.
package config

import (
"github.com/synapsecns/sanguine/ethergo/signer/config"
submitterConfig "github.com/synapsecns/sanguine/ethergo/submitter/config"
)

// Config represents the configuration of the application.
type Config struct {
// SlackBotToken is the token of the slack bot.
Expand All @@ -18,4 +23,20 @@ type Config struct {
SignozBaseURL string `yaml:"signoz_base_url"`
// RelayerURLS is the list of RFQ relayer URLs.
RelayerURLS []string `yaml:"rfq_relayer_urls"`
// RFQApiURL is the URL of the RFQ API.
RFQApiURL string `yaml:"rfq_api_url"`
// OmniRPCURL is the URL of the Omni RPC.
OmniRPCURL string `yaml:"omnirpc_url"`
// Signer is the signer config.
Signer config.SignerConfig `yaml:"signer"`
// SubmitterConfig is the submitter config.
SubmitterConfig submitterConfig.Config `yaml:"submitter_config"`
// Database is the database config.
Database DatabaseConfig `yaml:"database"`
}

// DatabaseConfig represents the configuration for the database.
type DatabaseConfig struct {
Type string `yaml:"type"`
DSN string `yaml:"dsn"` // Data Source Name
}
Loading

0 comments on commit b74114a

Please sign in to comment.