diff --git a/contrib/opbot/botmd/commands.go b/contrib/opbot/botmd/commands.go index 41c38cf429..84f45f161e 100644 --- a/contrib/opbot/botmd/commands.go +++ b/contrib/opbot/botmd/commands.go @@ -6,6 +6,14 @@ import ( "context" "errors" "fmt" + "log" + "math/big" + "regexp" + "strings" + "sync" + "time" + + "github.com/dustin/go-humanize" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -17,12 +25,6 @@ import ( 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" - "strings" - "sync" - "time" ) func (b *Bot) requiresSignoz(definition *slacker.CommandDefinition) *slacker.CommandDefinition { @@ -138,6 +140,7 @@ func (b *Bot) traceCommand() *slacker.CommandDefinition { }) } +// nolint: gocognit func (b *Bot) rfqLookupCommand() *slacker.CommandDefinition { return &slacker.CommandDefinition{ Command: "rfq ", @@ -204,7 +207,13 @@ func (b *Bot) rfqLookupCommand() *slacker.CommandDefinition { } var slackBlocks []slack.Block + for _, status := range statuses { + time, err := b.getTxAge(ctx, status.GetQuoteRequestStatusResponse) + if err != nil { + log.Printf("error getting tx age: %v\n", err) + } + objects := []*slack.TextBlockObject{ { Type: slack.MarkdownType, @@ -222,6 +231,10 @@ func (b *Bot) rfqLookupCommand() *slacker.CommandDefinition { Type: slack.MarkdownType, Text: fmt.Sprintf("*OriginTxHash*: %s", toTXSlackLink(status.OriginTxHash, status.OriginChainID)), }, + { + Type: slack.MarkdownType, + Text: fmt.Sprintf("*Estimated Tx Age*: %s", humanize.Time(time)), + }, } if status.DestTxHash == (common.Hash{}).String() { @@ -334,6 +347,25 @@ func (b *Bot) makeFastBridge(ctx context.Context, req *relapi.GetQuoteRequestRes return fastBridgeHandle, nil } +func (b *Bot) getTxAge(ctx *slacker.CommandContext, status *relapi.GetQuoteRequestStatusResponse) (time.Time, error) { + // TODO: add CreatedAt field to GetQuoteRequestStatusResponse so we don't need to make network calls? + client, err := b.rpcClient.GetChainClient(ctx.Context(), int(status.OriginChainID)) + if err != nil { + return time.Time{}, fmt.Errorf("error getting chain client: %w", err) + } + + receipt, err := client.TransactionReceipt(ctx.Context(), common.HexToHash(status.OriginTxHash)) + if err != nil { + return time.Time{}, fmt.Errorf("error fetching transaction receipt: %w", err) + } + txBlock, err := client.BlockByHash(ctx.Context(), receipt.BlockHash) + if err != nil { + return time.Time{}, fmt.Errorf("error fetching block by hash: %w", err) + } + + return time.Unix(int64(txBlock.Time()), 0), nil +} + func toExplorerSlackLink(ogHash string) string { rfqHash := strings.ToUpper(ogHash) // cut off 0x diff --git a/contrib/opbot/go.mod b/contrib/opbot/go.mod index 1cdcc292e0..c704413f2b 100644 --- a/contrib/opbot/go.mod +++ b/contrib/opbot/go.mod @@ -8,6 +8,7 @@ require ( github.com/charmbracelet/huh/spinner v0.0.0-20240618200428-90406d79077d github.com/davidmytton/url-verifier v1.0.1 github.com/dubonzi/otelresty v1.3.0 + github.com/dustin/go-humanize v1.0.1 github.com/ethereum/go-ethereum v1.13.8 github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a github.com/go-resty/resty/v2 v2.13.1 @@ -112,7 +113,6 @@ require ( github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/dennwc/varint v1.0.0 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/ethereum/c-kzg-4844 v0.4.0 // indirect