package prices import ( "errors" "strconv" "time" "github.com/gofiber/fiber/v2" "github.com/wormhole-foundation/wormhole-explorer/common/types" sdk "github.com/wormhole-foundation/wormhole/sdk/vaa" "go.uber.org/zap" ) type Controller struct { priceService *PriceService logger *zap.Logger } func NewController(priceService *PriceService, logger *zap.Logger) *Controller { return &Controller{ priceService: priceService, logger: logger, } } func (c *Controller) FindByToken(ctx *fiber.Ctx) error { chainID, err := extractChainID(ctx, c.logger) if err != nil { return err } tokenAddress, err := extractTokenAddress(ctx, c.logger) if err != nil { return err } dateTime, err := extractDatetime(ctx, c.logger) if err != nil { return err } price, err := c.priceService.GetPrice(ctx.Context(), *chainID, tokenAddress.Hex(), *dateTime) return c.handleResponse(err, ctx, price) } func (c *Controller) FindByCoingeckoID(ctx *fiber.Ctx) error { coingeckoID, err := extractCoingeckoID(ctx, c.logger) if err != nil { return err } dateTime, err := extractDatetime(ctx, c.logger) if err != nil { return err } price, err := c.priceService.GetPriceByCoingeckoID(ctx.Context(), coingeckoID, *dateTime) return c.handleResponse(err, ctx, price) } func (*Controller) handleResponse(err error, ctx *fiber.Ctx, price *Price) error { if err != nil { if errors.Is(err, ErrTokenNotFound) { return fiber.NewError(fiber.StatusNotFound, "token not found") } return err } return ctx.JSON(price) } func extractCoingeckoID(c *fiber.Ctx, l *zap.Logger) (string, error) { param := c.Params("coingeckoId") if param == "" { return "", fiber.NewError(fiber.StatusBadRequest, "missing coingeckoId parameter") } return param, nil } func extractChainID(c *fiber.Ctx, l *zap.Logger) (*sdk.ChainID, error) { param := c.Params("tokenChainId") if param == "" { return nil, fiber.NewError(fiber.StatusBadRequest, "missing tokenChainId parameter") } chain, err := strconv.ParseInt(param, 10, 16) if err != nil { l.Error("failed to parse tokenChainId parameter", zap.Error(err), ) return nil, fiber.NewError(fiber.StatusBadRequest, "invalid chain id parameter") } result := sdk.ChainID(chain) return &result, nil } func extractTokenAddress(c *fiber.Ctx, l *zap.Logger) (*types.Address, error) { tokenAddressStr := c.Params("tokenAddress") tokenAddress, err := types.StringToAddress(tokenAddressStr, true) if err != nil { l.Error("failed to convert token address to wormhole address", zap.Error(err), zap.String("tokenAddressStr", tokenAddressStr)) return nil, fiber.NewError(fiber.StatusBadRequest, "invalid token address") } return tokenAddress, nil } func extractDatetime(c *fiber.Ctx, l *zap.Logger) (*time.Time, error) { datetime := c.Params("datetime") if datetime == "" { return nil, fiber.NewError(fiber.StatusBadRequest, "missing datetime parameter") } v, err := time.Parse(time.RFC3339, datetime) if err != nil { return nil, fiber.NewError(fiber.StatusBadRequest, "invalid datetime parameter") } if v.After(time.Now()) { return nil, fiber.NewError(fiber.StatusBadRequest, "datetime must be in the past") } return &v, nil }