services/explorer/api/server.go
package api
import (
"context"
"encoding/json"
"fmt"
"github.com/synapsecns/sanguine/core/metrics/instrumentation/httpcapture"
"net"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/gin-gonic/gin"
"github.com/ipfs/go-log"
"github.com/synapsecns/sanguine/core/metrics"
etherClient "github.com/synapsecns/sanguine/ethergo/client"
"github.com/synapsecns/sanguine/services/explorer/consumer/fetcher/tokenprice"
"github.com/synapsecns/sanguine/services/explorer/consumer/parser"
"github.com/synapsecns/sanguine/services/explorer/consumer/parser/tokendata"
"github.com/synapsecns/sanguine/services/explorer/contracts/bridge"
"github.com/synapsecns/sanguine/services/explorer/contracts/bridgeconfig"
"github.com/synapsecns/sanguine/services/explorer/contracts/cctp"
"github.com/synapsecns/sanguine/services/explorer/contracts/fastbridge"
"github.com/synapsecns/sanguine/services/explorer/contracts/swap"
"github.com/synapsecns/sanguine/services/explorer/static"
"github.com/synapsecns/sanguine/services/explorer/types"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"github.com/synapsecns/sanguine/core/ginhelper"
"github.com/synapsecns/sanguine/services/explorer/api/cache"
"github.com/synapsecns/sanguine/services/explorer/graphql/server/graph/model"
"net/http"
baseServer "github.com/synapsecns/sanguine/core/server"
serverConfig "github.com/synapsecns/sanguine/services/explorer/config/server"
"github.com/synapsecns/sanguine/services/explorer/consumer/client"
fetcherpkg "github.com/synapsecns/sanguine/services/explorer/consumer/fetcher"
"github.com/synapsecns/sanguine/services/explorer/db"
"github.com/synapsecns/sanguine/services/explorer/db/sql"
gqlClient "github.com/synapsecns/sanguine/services/explorer/graphql/client"
gqlServer "github.com/synapsecns/sanguine/services/explorer/graphql/server"
"github.com/synapsecns/sanguine/services/explorer/testutil/clickhouse"
"golang.org/x/sync/errgroup"
)
const cacheRehydrationInterval = 1800
var logger = log.Logger("explorer-api")
// nolint:gocognit,cyclop
func createParsers(ctx context.Context, db db.ConsumerDB, fetcher fetcherpkg.ScribeFetcher, clients map[uint32]etherClient.EVM, config serverConfig.Config) (*types.ServerParsers, *types.ServerRefs, map[string]*swap.SwapFlashLoanFilterer, error) {
ethClient, err := ethclient.DialContext(ctx, config.RPCURL+fmt.Sprintf("%d", 1))
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create client: %w", err)
}
bridgeConfigRef, err := bridgeconfig.NewBridgeConfigRef(common.HexToAddress(config.BridgeConfigAddress), ethClient)
if err != nil || bridgeConfigRef == nil {
return nil, nil, nil, fmt.Errorf("could not create bridge config ScribeFetcher: %w", err)
}
priceDataService, err := tokenprice.NewPriceDataService()
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create price data service: %w", err)
}
newConfigFetcher, err := fetcherpkg.NewBridgeConfigFetcher(common.HexToAddress(config.BridgeConfigAddress), bridgeConfigRef)
if err != nil || newConfigFetcher == nil {
return nil, nil, nil, fmt.Errorf("could not get bridge abi: %w", err)
}
tokenSymbolToIDs, err := parser.ParseYaml(static.GetTokenSymbolToTokenIDConfig())
if err != nil {
return nil, nil, nil, fmt.Errorf("could not open yaml file: %w", err)
}
tokenDataService, err := tokendata.NewTokenDataService(newConfigFetcher, tokenSymbolToIDs)
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create token data service: %w", err)
}
fastbridgeParsers := make(map[uint32]*parser.RFQParser)
fastbridgeRefs := make(map[uint32]*fastbridge.FastBridgeRef)
cctpParsers := make(map[uint32]*parser.CCTPParser)
bridgeParsers := make(map[uint32]*parser.BridgeParser)
bridgeRefs := make(map[uint32]*bridge.BridgeRef)
cctpRefs := make(map[uint32]*cctp.CCTPRef)
swapFilterers := make(map[string]*swap.SwapFlashLoanFilterer)
for _, chain := range config.Chains {
if chain.Contracts.CCTP != "" {
cctpService, err := fetcherpkg.NewCCTPFetcher(common.HexToAddress(chain.Contracts.CCTP), clients[chain.ChainID])
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create cctp fetcher: %w", err)
}
cctpRef, err := cctp.NewCCTPRef(common.HexToAddress(chain.Contracts.CCTP), clients[chain.ChainID])
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create cctp ref: %w", err)
}
cctpRefs[chain.ChainID] = cctpRef
cctpParser, err := parser.NewCCTPParser(db, common.HexToAddress(chain.Contracts.CCTP), fetcher, cctpService, tokenDataService, priceDataService, true)
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create cctp parser: %w", err)
}
cctpParsers[chain.ChainID] = cctpParser
}
if chain.Contracts.Bridge != "" {
bridgeRef, err := bridge.NewBridgeRef(common.HexToAddress(chain.Contracts.Bridge), clients[chain.ChainID])
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create bridge ref: %w", err)
}
bridgeRefs[chain.ChainID] = bridgeRef
bridgeParser, err := parser.NewBridgeParser(db, common.HexToAddress(chain.Contracts.Bridge), tokenDataService, fetcher, priceDataService, true)
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create bridge parser: %w", err)
}
bridgeParsers[chain.ChainID] = bridgeParser
}
if chain.Contracts.RFQ != "" {
rfqService, err := fetcherpkg.NewRFQFetcher(common.HexToAddress(chain.Contracts.RFQ), clients[chain.ChainID])
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create fast bridge fetcher: %w", err)
}
fastBridgeRef, err := fastbridge.NewFastBridgeRef(common.HexToAddress(chain.Contracts.RFQ), clients[chain.ChainID])
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create fast bridge ref: %w", err)
}
fastbridgeRefs[chain.ChainID] = fastBridgeRef
rfqParser, err := parser.NewRFQParser(db, common.HexToAddress(chain.Contracts.RFQ), fetcher, rfqService, tokenDataService, priceDataService, true)
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create fast bridge parser: %w", err)
}
fastbridgeParsers[chain.ChainID] = rfqParser
}
if len(chain.Swaps) > 0 {
for _, swapAddr := range chain.Swaps {
swapFilterer, err := swap.NewSwapFlashLoanFilterer(common.HexToAddress(swapAddr), clients[chain.ChainID])
if err != nil {
return nil, nil, nil, fmt.Errorf("could not create swap filterer: %w", err)
}
key := fmt.Sprintf("%d_%s", chain.ChainID, swapAddr)
swapFilterers[key] = swapFilterer
}
}
}
serverParser := types.ServerParsers{
BridgeParsers: bridgeParsers,
CCTParsers: cctpParsers,
FastBridgeParsers: fastbridgeParsers,
}
serverRefs := types.ServerRefs{
BridgeRefs: bridgeRefs,
CCTPRefs: cctpRefs,
FastBridgeRefs: fastbridgeRefs,
}
return &serverParser, &serverRefs, swapFilterers, nil
}
// Start starts the api server.
//
// nolint:cyclop
func Start(ctx context.Context, cfg serverConfig.Config, handler metrics.Handler) error {
router := ginhelper.New(logger)
router.GET(ginhelper.MetricsEndpoint, gin.WrapH(handler.Handler()))
// initialize the database
consumerDB, err := InitDB(ctx, cfg.DBAddress, true, handler)
if err != nil {
return fmt.Errorf("could not initialize database: %w", err)
}
// configure the http client
httpClient := http.DefaultClient
// TODO: add an option for full capture instead of keeping on by default
httpClient.Transport = httpcapture.NewCaptureTransport(httpClient.Transport, handler)
handler.ConfigureHTTPClient(httpClient)
// get the fetcher
fetcher := fetcherpkg.NewFetcher(client.NewClient(httpClient, cfg.ScribeURL), handler)
// response cache
responseCache, err := cache.NewAPICacheService()
if err != nil {
return fmt.Errorf("error creating api cache service, %w", err)
}
clients := make(map[uint32]etherClient.EVM)
for _, chain := range cfg.Chains {
backendClient, err := etherClient.DialBackend(ctx, cfg.RPCURL+fmt.Sprintf("%d", chain.ChainID), handler)
if err != nil {
return fmt.Errorf("could not start client for %s", cfg.RPCURL)
}
clients[chain.ChainID] = backendClient
}
serverParsers, serverRefs, swapFilters, err := createParsers(ctx, consumerDB, fetcher, clients, cfg)
if err != nil {
return fmt.Errorf("could not create parsers: %w", err)
}
gqlServer.EnableGraphql(router, consumerDB, fetcher, responseCache, clients, serverParsers, serverRefs, swapFilters, cfg, handler)
fmt.Printf("started graphiql gqlServer on port: http://localhost:%d/graphiql\n", cfg.HTTPPort)
ticker := time.NewTicker(cacheRehydrationInterval * time.Second)
defer ticker.Stop()
first := make(chan bool, 1)
first <- true
g, ctx := errgroup.WithContext(ctx)
url := fmt.Sprintf("http://%s/graphql", net.JoinHostPort("localhost", fmt.Sprintf("%d", cfg.HTTPPort)))
client := gqlClient.NewClient(httpClient, url)
err = registerObservableMetrics(handler, consumerDB)
if err != nil {
return fmt.Errorf("could not register observable metrics: %w", err)
}
if cfg.HydrateCache {
// refill cache
go func() {
for {
select {
case <-ctx.Done():
ticker.Stop()
return
case <-ticker.C:
err = RehydrateCache(ctx, client, responseCache, handler)
if err != nil {
logger.Warnf("rehydration failed: %s", err)
}
case <-first:
// buffer to wait for everything to get initialized
time.Sleep(10 * time.Second)
err = RehydrateCache(ctx, client, responseCache, handler)
if err != nil {
logger.Errorf("initial rehydration failed: %s", err)
}
}
}
}()
}
g.Go(func() error {
connection := baseServer.Server{}
err = connection.ListenAndServe(ctx, fmt.Sprintf(":%d", cfg.HTTPPort), router)
if err != nil {
return fmt.Errorf("could not start gqlServer: %w", err)
}
return nil
})
err = g.Wait()
if err != nil {
return fmt.Errorf("server error: %w", err)
}
return nil
}
const meterName = "github.com/synapsecns/sanguine/services/explorer/api"
const pendingName = "pending_bridges"
func registerObservableMetrics(handler metrics.Handler, conn db.ConsumerDBReader) error {
meter := handler.Meter(meterName)
pendingGauge, err := meter.Int64ObservableGauge(pendingName)
if err != nil {
return fmt.Errorf("could not create pending bridges gauge: %w", err)
}
if _, err := meter.RegisterCallback(func(parentCtx context.Context, o metric.Observer) (err error) {
ctx, span := handler.Tracer().Start(parentCtx, "pending_bridge_stats")
defer func() {
metrics.EndSpanWithErr(span, err)
}()
pendingCount, err := conn.GetPendingByChain(ctx)
if err != nil {
return fmt.Errorf("could not get pending bridges: %w", err)
}
itr := pendingCount.Iterator()
for !itr.Done() {
chainID, count, _ := itr.Next()
o.ObserveInt64(pendingGauge, int64(count), metric.WithAttributes(attribute.Int(metrics.ChainID, chainID)))
}
return nil
}, pendingGauge); err != nil {
return fmt.Errorf("could not register callback for pending bridges gauge: %w", err)
}
return nil
}
// InitDB initializes a database given a database type and path.
func InitDB(ctx context.Context, address string, readOnly bool, handler metrics.Handler) (db.ConsumerDB, error) {
if address == "default" {
cleanup, port, err := clickhouse.NewClickhouseStore("explorer")
if cleanup == nil {
return nil, fmt.Errorf("clickhouse spin up failure, no open port found: %w", err)
}
if port == nil || err != nil {
cleanup()
return nil, fmt.Errorf("clickhouse spin up failure, no open port found: %w", err)
}
address = "clickhouse://clickhouse_test:clickhouse_test@localhost:" + fmt.Sprintf("%d", *port) + "/clickhouse_test"
}
clickhouseDB, err := sql.OpenGormClickhouse(ctx, address, readOnly, handler)
if err != nil {
return nil, fmt.Errorf("could not open database: %w", err)
}
return clickhouseDB, nil
}
// TODO make this nicer. make a yaml of the queries needed for rehydration w/refresh rate and iterate on that.
// RehydrateCache rehydrates the cache.
//
// nolint:dupl,gocognit,cyclop,maintidx
func RehydrateCache(parentCtx context.Context, client *gqlClient.Client, service cache.Service, handler metrics.Handler) (err error) {
traceCtx, span := handler.Tracer().Start(parentCtx, "RehydrateCache")
defer func() {
metrics.EndSpanWithErr(span, err)
}()
fmt.Println("rehydrating Cache")
totalVolumeType := model.StatisticTypeTotalVolumeUsd
totalFeeType := model.StatisticTypeTotalFeeUsd
countAddressType := model.StatisticTypeCountAddresses
countTxType := model.StatisticTypeCountTransactions
allPlatformType := model.PlatformAll
bridgeType := model.PlatformBridge
swapType := model.PlatformSwap
messagingType := model.PlatformMessageBus
volumeType := model.DailyStatisticTypeVolume
feeType := model.DailyStatisticTypeFee
txType := model.DailyStatisticTypeTransactions
addrType := model.DailyStatisticTypeAddresses
monthType := model.DurationPastMonth
threeMonthType := model.DurationPast3Months
sixMonthType := model.DurationPast6Months
allTimeType := model.DurationAllTime
// dontUseMv := false
useMv := true
g, ctx := errgroup.WithContext(traceCtx)
g.Go(func() error {
statsVolAll, err := client.GetAmountStatistic(ctx, totalVolumeType, &allPlatformType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, TOTAL_VOLUME_USD, ALL, ALL_TIME, , , ", HandleJSONAmountStat(statsVolAll))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
statsFeeAll, err := client.GetAmountStatistic(ctx, totalFeeType, &allPlatformType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, TOTAL_FEE_USD, ALL, ALL_TIME, , , ", HandleJSONAmountStat(statsFeeAll))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
statsAddrAll, err := client.GetAmountStatistic(ctx, countAddressType, &allPlatformType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, COUNT_ADDRESSES, ALL, ALL_TIME, , , ", HandleJSONAmountStat(statsAddrAll))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
statsTxAll, err := client.GetAmountStatistic(ctx, countTxType, &allPlatformType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, COUNT_TRANSACTIONS, ALL, ALL_TIME, , , ", HandleJSONAmountStat(statsTxAll))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
statsVolBridge, err := client.GetAmountStatistic(ctx, totalVolumeType, &bridgeType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, TOTAL_VOLUME_USD, BRIDGE, ALL_TIME, , , ", HandleJSONAmountStat(statsVolBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
statsFeeBridge, err := client.GetAmountStatistic(ctx, totalFeeType, &bridgeType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, TOTAL_FEE_USD, BRIDGE, ALL_TIME, , , ", HandleJSONAmountStat(statsFeeBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
statsAddrBridge, err := client.GetAmountStatistic(ctx, countAddressType, &bridgeType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, COUNT_ADDRESSES, BRIDGE, ALL_TIME, , , ", HandleJSONAmountStat(statsAddrBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
statsTxBridge, err := client.GetAmountStatistic(ctx, countTxType, &bridgeType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, COUNT_TRANSACTIONS, BRIDGE, ALL_TIME, , , ", HandleJSONAmountStat(statsTxBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
statsVolSwap, err := client.GetAmountStatistic(ctx, totalVolumeType, &swapType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, TOTAL_VOLUME_USD, SWAP, ALL_TIME, , , ", HandleJSONAmountStat(statsVolSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
statsFeeSwap, err := client.GetAmountStatistic(ctx, totalFeeType, &swapType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, TOTAL_FEE_USD, SWAP, ALL_TIME, , , ", HandleJSONAmountStat(statsFeeSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
statsAddrSwap, err := client.GetAmountStatistic(ctx, countAddressType, &swapType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, COUNT_ADDRESSES, SWAP, ALL_TIME, , , ", HandleJSONAmountStat(statsAddrSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
statsTxSwap, err := client.GetAmountStatistic(ctx, countTxType, &swapType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, COUNT_TRANSACTIONS, SWAP, ALL_TIME, , , ", HandleJSONAmountStat(statsTxSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
statsFeeMsg, err := client.GetAmountStatistic(ctx, totalFeeType, &messagingType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, TOTAL_FEE_USD, MESSAGE_BUS, ALL_TIME, , , ", HandleJSONAmountStat(statsFeeMsg))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
statsAddrMsg, err := client.GetAmountStatistic(ctx, countAddressType, &messagingType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, COUNT_ADDRESSES, MESSAGE_BUS, ALL_TIME, , , ", HandleJSONAmountStat(statsAddrMsg))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
statsTxMsg, err := client.GetAmountStatistic(ctx, countTxType, &messagingType, &allTimeType, nil, nil, nil, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("amountStatistic, COUNT_TRANSACTIONS, MESSAGE_BUS, ALL_TIME, , , ", HandleJSONAmountStat(statsTxMsg))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyVolMonth, err := client.GetDailyStatisticsByChain(ctx, nil, &volumeType, &monthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , VOLUME, PAST_MONTH, ALL", HandleJSONDailyStat(dailyVolMonth))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyFeeMonth, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &monthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_MONTH, ALL", HandleJSONDailyStat(dailyFeeMonth))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxMonth, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &monthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_MONTH, ALL", HandleJSONDailyStat(dailyTxMonth))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrMonth, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &monthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_MONTH, ALL", HandleJSONDailyStat(dailyAddrMonth))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyVolYear, err := client.GetDailyStatisticsByChain(ctx, nil, &volumeType, &threeMonthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , VOLUME, PAST_3_MONTHS, ALL", HandleJSONDailyStat(dailyVolYear))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyFeeYear, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &threeMonthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_3_MONTHS, ALL", HandleJSONDailyStat(dailyFeeYear))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxYear, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &threeMonthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_3_MONTHS, ALL", HandleJSONDailyStat(dailyTxYear))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrYear, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &threeMonthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_3_MONTHS, ALL", HandleJSONDailyStat(dailyAddrYear))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyVolAllTime, err := client.GetDailyStatisticsByChain(ctx, nil, &volumeType, &sixMonthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , VOLUME, PAST_6_MONTHS, ALL", HandleJSONDailyStat(dailyVolAllTime))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyFeeAllTime, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &sixMonthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_6_MONTHS, ALL", HandleJSONDailyStat(dailyFeeAllTime))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxAllTime, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &sixMonthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_6_MONTHS, ALL", HandleJSONDailyStat(dailyTxAllTime))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrAllTime, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &sixMonthType, &allPlatformType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_6_MONTHS, ALL", HandleJSONDailyStat(dailyAddrAllTime))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyVolMonthBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &volumeType, &monthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , VOLUME, PAST_MONTH, BRIDGE", HandleJSONDailyStat(dailyVolMonthBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyFeeMonthBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &monthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_MONTH, BRIDGE", HandleJSONDailyStat(dailyFeeMonthBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxMonthBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &monthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_MONTH, BRIDGE", HandleJSONDailyStat(dailyTxMonthBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrMonthBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &monthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_MONTH, BRIDGE", HandleJSONDailyStat(dailyAddrMonthBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyVolYearBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &volumeType, &threeMonthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , VOLUME, PAST_3_MONTHS, BRIDGE", HandleJSONDailyStat(dailyVolYearBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyFeeYearBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &threeMonthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_3_MONTHS, BRIDGE", HandleJSONDailyStat(dailyFeeYearBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxYearBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &threeMonthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_3_MONTHS, BRIDGE", HandleJSONDailyStat(dailyTxYearBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrYearBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &threeMonthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_3_MONTHS, BRIDGE", HandleJSONDailyStat(dailyAddrYearBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyVolAllTimeBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &volumeType, &sixMonthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , VOLUME, PAST_6_MONTHS, BRIDGE", HandleJSONDailyStat(dailyVolAllTimeBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyFeeAllTimeBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &sixMonthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_6_MONTHS, BRIDGE", HandleJSONDailyStat(dailyFeeAllTimeBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxAllTimeBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &sixMonthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_6_MONTHS, BRIDGE", HandleJSONDailyStat(dailyTxAllTimeBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrAllTimeBridge, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &sixMonthType, &bridgeType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_6_MONTHS, BRIDGE", HandleJSONDailyStat(dailyAddrAllTimeBridge))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyVolMonthSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &volumeType, &monthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , VOLUME, PAST_MONTH, SWAP", HandleJSONDailyStat(dailyVolMonthSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyFeeMonthSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &monthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_MONTH, SWAP", HandleJSONDailyStat(dailyFeeMonthSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxMonthSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &monthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_MONTH, SWAP", HandleJSONDailyStat(dailyTxMonthSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrMonthSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &monthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_MONTH, SWAP", HandleJSONDailyStat(dailyAddrMonthSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyVolYearSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &volumeType, &threeMonthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , VOLUME, PAST_3_MONTHS, SWAP", HandleJSONDailyStat(dailyVolYearSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyFeeYearSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &threeMonthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_3_MONTHS, SWAP", HandleJSONDailyStat(dailyFeeYearSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxYearSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &threeMonthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_3_MONTHS, SWAP", HandleJSONDailyStat(dailyTxYearSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrYearSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &threeMonthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_3_MONTHS, SWAP", HandleJSONDailyStat(dailyAddrYearSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyVolAllTimeSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &volumeType, &sixMonthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , VOLUME, PAST_6_MONTHS, SWAP", HandleJSONDailyStat(dailyVolAllTimeSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyFeeAllTimeSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &sixMonthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_6_MONTHS, SWAP", HandleJSONDailyStat(dailyFeeAllTimeSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxAllTimeSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &sixMonthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_6_MONTHS, SWAP", HandleJSONDailyStat(dailyTxAllTimeSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrAllTimeSwap, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &sixMonthType, &swapType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_6_MONTHS, SWAP", HandleJSONDailyStat(dailyAddrAllTimeSwap))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyFeeMonthMessageBus, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &monthType, &messagingType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_MONTH, MESSAGE_BUS", HandleJSONDailyStat(dailyFeeMonthMessageBus))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxMonthMessageBus, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &monthType, &messagingType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_MONTH, MESSAGE_BUS", HandleJSONDailyStat(dailyTxMonthMessageBus))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrMonthMessageBus, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &monthType, &messagingType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_MONTH, MESSAGE_BUS", HandleJSONDailyStat(dailyAddrMonthMessageBus))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyFeeYearMessageBus, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &threeMonthType, &messagingType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_3_MONTHS, MESSAGE_BUS", HandleJSONDailyStat(dailyFeeYearMessageBus))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxYearMessageBus, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &threeMonthType, &messagingType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_3_MONTHS, MESSAGE_BUS", HandleJSONDailyStat(dailyTxYearMessageBus))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrYearMessageBus, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &threeMonthType, &messagingType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_3_MONTHS, MESSAGE_BUS", HandleJSONDailyStat(dailyAddrYearMessageBus))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
g.Go(func() error {
dailyFeeAllTimeMessageBus, err := client.GetDailyStatisticsByChain(ctx, nil, &feeType, &sixMonthType, &messagingType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , FEE, PAST_6_MONTHS, MESSAGE_BUS", HandleJSONDailyStat(dailyFeeAllTimeMessageBus))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyTxAllTimeMessageBus, err := client.GetDailyStatisticsByChain(ctx, nil, &txType, &sixMonthType, &messagingType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , TRANSACTIONS, PAST_6_MONTHS, MESSAGE_BUS", HandleJSONDailyStat(dailyTxAllTimeMessageBus))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
dailyAddrAllTimeMessageBus, err := client.GetDailyStatisticsByChain(ctx, nil, &addrType, &sixMonthType, &messagingType, &useMv)
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
err = service.CacheResponse("dailyStatisticsByChain, , ADDRESSES, PAST_6_MONTHS, MESSAGE_BUS", HandleJSONDailyStat(dailyAddrAllTimeMessageBus))
if err != nil {
return fmt.Errorf("error rehydrating cache: %w", err)
}
return nil
})
err = g.Wait()
if err != nil {
return fmt.Errorf("error rehyrdrating cache, %w", err)
}
return nil
}
// HandleJSONAmountStat converts the gqlClient.GetAmountStatistic to model.ValueResul.
func HandleJSONAmountStat(r *gqlClient.GetAmountStatistic) *model.ValueResult {
var res *model.ValueResult
jsonRes, err := json.Marshal(r.Response)
if err != nil {
return nil
}
err = json.Unmarshal(jsonRes, &res)
if err != nil {
return nil
}
return res
}
// HandleJSONDailyStat converts the gqlClient.GetDailyStatisticsByChain to the []*model.DateResultByChain type.
func HandleJSONDailyStat(r *gqlClient.GetDailyStatisticsByChain) []*model.DateResultByChain {
var res []*model.DateResultByChain
jsonRes, err := json.Marshal(r.Response)
if err != nil {
return nil
}
err = json.Unmarshal(jsonRes, &res)
if err != nil {
return nil
}
return res
}