wormhole-explorer/notional/prices/controller.go

126 lines
3.2 KiB
Go

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
}