wormhole-explorer/api/routes/wormscan/vaa/controller.go

273 lines
7.4 KiB
Go

// Package observations handle the request of VAA data from governor endpoint defined in the api.
package vaa
import (
"encoding/base64"
"strconv"
"github.com/gofiber/fiber/v2"
"github.com/pkg/errors"
"github.com/wormhole-foundation/wormhole-explorer/api/handlers/vaa"
"github.com/wormhole-foundation/wormhole-explorer/api/middleware"
"github.com/wormhole-foundation/wormhole-explorer/api/response"
_ "github.com/wormhole-foundation/wormhole-explorer/api/response" // required by swaggo
"go.uber.org/zap"
)
// Controller definition.
type Controller struct {
srv *vaa.Service
logger *zap.Logger
}
// NewController create a new controler.
func NewController(serv *vaa.Service, logger *zap.Logger) *Controller {
return &Controller{srv: serv, logger: logger.With(zap.String("module", "VaaController"))}
}
// FindAll godoc
// @Description Returns all VAAs. Output is paginated and can also be be sorted.
// @Tags wormholescan
// @ID find-all-vaas
// @Param page query integer false "Page number."
// @Param pageSize query integer false "Number of elements per page."
// @Param sortOrder query string false "Sort results in ascending or descending order." Enums(ASC, DESC)
// @Param txHash query string false "Transaction hash of the VAA"
// @Param parsedPayload query bool false "include the parsed contents of the VAA, if available"
// @Param appId query string false "filter by application ID"
// @Success 200 {object} response.Response[[]vaa.VaaDoc]
// @Failure 400
// @Failure 500
// @Router /api/v1/vaas/ [get]
func (c *Controller) FindAll(ctx *fiber.Ctx) error {
pagination, err := middleware.ExtractPagination(ctx)
if err != nil {
return err
}
// Check pagination max limit
if pagination.Limit > 1000 {
return response.NewInvalidParamError(ctx, "pageSize cannot be greater than 1000", nil)
}
txHash, err := middleware.GetTxHash(ctx, c.logger)
if err != nil {
return err
}
includeParsedPayload, err := middleware.ExtractParsedPayload(ctx, c.logger)
if err != nil {
return err
}
appId := middleware.ExtractAppId(ctx, c.logger)
if appId != "" {
includeParsedPayload = true
}
p := vaa.FindAllParams{
Pagination: pagination,
TxHash: txHash,
IncludeParsedPayload: includeParsedPayload,
AppId: appId,
}
vaas, err := c.srv.FindAll(ctx.Context(), &p)
if err != nil {
return err
}
return ctx.JSON(vaas)
}
// FindByChain godoc
// @Description Returns all the VAAs generated in specific blockchain.
// @Tags wormholescan
// @ID find-vaas-by-chain
// @Param chain_id path integer true "id of the blockchain"
// @Param page query integer false "Page number."
// @Param pageSize query integer false "Number of elements per page."
// @Param sortOrder query string false "Sort results in ascending or descending order." Enums(ASC, DESC)
// @Success 200 {object} response.Response[[]vaa.VaaDoc]
// @Failure 400
// @Failure 500
// @Router /api/v1/vaas/:chain_id [get]
func (c *Controller) FindByChain(ctx *fiber.Ctx) error {
p, err := middleware.ExtractPagination(ctx)
if err != nil {
return err
}
// Check pagination max limit
if p.Limit > 1000 {
return response.NewInvalidParamError(ctx, "pageSize cannot be greater than 1000", nil)
}
chainID, err := middleware.ExtractChainID(ctx, c.logger)
if err != nil {
return err
}
vaas, err := c.srv.FindByChain(ctx.Context(), chainID, p)
if err != nil {
return err
}
return ctx.JSON(vaas)
}
// FindByEmitter godoc
// @Description Returns all all the VAAs generated by a specific emitter address.
// @Tags wormholescan
// @ID find-vaas-by-emitter
// @Param chain_id path integer true "id of the blockchain"
// @Param emitter path string true "address of the emitter"
// @Param toChain query integer false "destination chain"
// @Param page query integer false "Page number."
// @Param pageSize query integer false "Number of elements per page."
// @Param sortOrder query string false "Sort results in ascending or descending order." Enums(ASC, DESC)
// @Success 200 {object} response.Response[[]vaa.VaaDoc]
// @Failure 400
// @Failure 500
// @Router /api/v1/vaas/:chain_id/:emitter [get]
func (c *Controller) FindByEmitter(ctx *fiber.Ctx) error {
// Get query parameters
pagination, err := middleware.ExtractPagination(ctx)
if err != nil {
return err
}
// Check pagination max limit
if pagination.Limit > 1000 {
return response.NewInvalidParamError(ctx, "pageSize cannot be greater than 1000", nil)
}
chainID, emitter, err := middleware.ExtractVAAChainIDEmitter(ctx, c.logger)
if err != nil {
return err
}
toChain, err := middleware.ExtractToChain(ctx, c.logger)
if err != nil {
return err
}
includeParsedPayload, err := middleware.ExtractParsedPayload(ctx, c.logger)
if err != nil {
return err
}
// Call the VAA service
p := vaa.FindByEmitterParams{
EmitterChain: chainID,
EmitterAddress: emitter,
ToChain: toChain,
IncludeParsedPayload: includeParsedPayload,
Pagination: pagination,
}
vaas, err := c.srv.FindByEmitter(ctx.Context(), &p)
if err != nil {
return err
}
return ctx.JSON(vaas)
}
// FindById godoc
// @Description Find a VAA by ID.
// @Tags wormholescan
// @ID find-vaa-by-id
// @Param chain_id path integer true "id of the blockchain"
// @Param emitter path string true "address of the emitter"
// @Param seq path integer true "sequence of the VAA"
// @Param parsedPayload query bool false "include the parsed contents of the VAA, if available"
// @Success 200 {object} response.Response[[]vaa.VaaDoc]
// @Failure 400
// @Failure 500
// @Router /api/v1/vaas/:chain_id/:emitter/:seq [get]
func (c *Controller) FindById(ctx *fiber.Ctx) error {
chainID, emitter, seq, err := middleware.ExtractVAAParams(ctx, c.logger)
if err != nil {
return err
}
includeParsedPayload, err := middleware.ExtractParsedPayload(ctx, c.logger)
if err != nil {
return err
}
vaa, err := c.srv.FindById(
ctx.Context(),
chainID,
emitter,
strconv.FormatUint(seq, 10),
includeParsedPayload,
)
if err != nil {
return err
}
return ctx.JSON(vaa)
}
// GetVaaCount godoc
// @Description Returns the total number of VAAs emitted for each blockchain.
// @Tags wormholescan
// @ID get-vaa-counts
// @Success 200 {object} response.Response[[]vaa.VaaStats]
// @Failure 400
// @Failure 500
// @Router /api/v1/vaas/vaa-counts [get]
func (c *Controller) GetVaaCount(ctx *fiber.Ctx) error {
vaas, err := c.srv.GetVaaCount(ctx.Context())
if err != nil {
return err
}
return ctx.JSON(vaas)
}
// ParseVaa godoc
// @Description Parse a VAA.
// @Tags wormholescan
// @ID parse-vaa
// @Success 200 {object} parser.ParseVaaWithStandarizedPropertiesdResponse
// @Failure 400
// @Failure 404
// @Failure 500
// @Router /api/v1/vaas/parse [post]
func (c *Controller) ParseVaa(ctx *fiber.Ctx) error {
parseVaaBody := struct {
Vaa string `json:"vaa"`
}{}
err := ctx.BodyParser(&parseVaaBody)
if err != nil {
return response.NewRequestBodyError(ctx,
"invalid vaa request, unable to parse",
errors.WithStack(err))
}
if len(parseVaaBody.Vaa) == 0 {
return response.NewRequestBodyError(
ctx,
"invalid vaa request, vaa is empty",
nil)
}
vaa, err := base64.StdEncoding.DecodeString(parseVaaBody.Vaa)
if err != nil {
return response.NewRequestBodyError(ctx,
"invalid vaa request, vaa is not base64 encoded",
errors.WithStack(err))
}
parsedVaa, err := c.srv.ParseVaa(ctx.Context(), vaa)
if err != nil {
return err
}
return ctx.JSON(parsedVaa)
}