Skip to content

Commit 9d99c4d

Browse files
committed
feat(api): add endpoint to get truncated guest dashboard validators
1 parent 979a973 commit 9d99c4d

File tree

4 files changed

+72
-1
lines changed

4 files changed

+72
-1
lines changed

backend/pkg/api/handlers/validator_dashboard.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ package handlers
22

33
import (
44
"context"
5+
"fmt"
56
"io"
7+
"maps"
8+
"math/big"
9+
"slices"
610
"time"
711

812
"github.com/gobitfly/beaconchain/pkg/api/enums"
913
"github.com/gobitfly/beaconchain/pkg/api/types"
14+
"github.com/gobitfly/beaconchain/pkg/commons/utils"
15+
"github.com/shopspring/decimal"
1016
)
1117

1218
// PostValidatorDashboardGroups godoc
@@ -587,3 +593,55 @@ func (h *HandlerService) GetValidatorDashboardTotalConsensusLayerDeposits(ctx co
587593
r.Data = *data
588594
return r, nil
589595
}
596+
597+
// GetTruncatedGuestValidatorDashboard godoc
598+
//
599+
// @Description Get validators (ordered by index) eligible for the guest dashboard's free tier, stopping once their total effective balance meets the tier's balance limit.
600+
//
601+
// @Tags Validator Dashboard
602+
// @Produce json
603+
// @Param validators query string true "Provide a comma separated list of validator indices or public keys to put into the dashboard."
604+
// @Success 200 {object} types.GetTruncatedGuestValidatorDashboardResponse
605+
// @Failure 400 {object} types.ApiErrorResponse
606+
// @Router /truncated-guest-validator-dashboard [get]
607+
func (i *inputGetTruncatedGuestValidatorDashboard) Validate(params map[string]string, _ io.ReadCloser) error {
608+
var v validationError
609+
i.validatorIndices, i.publicKeys = v.checkValidatorList(params["validators"], allowEmpty)
610+
return v.AsError()
611+
}
612+
613+
type inputGetTruncatedGuestValidatorDashboard struct {
614+
validatorIndices []types.VDBValidator
615+
publicKeys []string
616+
}
617+
618+
func (h *HandlerService) GetTruncatedGuestValidatorDashboard(ctx context.Context, input inputGetTruncatedGuestValidatorDashboard) (types.GetTruncatedGuestValidatorDashboardResponse, error) {
619+
var r types.GetTruncatedGuestValidatorDashboardResponse
620+
621+
requestedValidators, err := h.getDataAccessor(ctx).GetValidatorsFromSlices(ctx, input.validatorIndices, input.publicKeys)
622+
if err != nil {
623+
return r, fmt.Errorf("failed to get requested validators: %w", err)
624+
}
625+
626+
effectiveBalancesMap, err := h.getDataAccessor(ctx).GetValidatorsEffectiveBalances(ctx, requestedValidators, true)
627+
if err != nil {
628+
return r, fmt.Errorf("failed to get effective balances: %w", err)
629+
}
630+
631+
perks, err := h.daService.GetFreeTierPerks(ctx)
632+
if err != nil {
633+
return r, fmt.Errorf("failed to get free tier perks: %w", err)
634+
}
635+
636+
var truncatedValidators []uint64
637+
var totalBalance decimal.Decimal
638+
for _, index := range slices.Sorted(maps.Keys(effectiveBalancesMap)) { // iterate over ascending order of indices
639+
totalBalance = totalBalance.Add(utils.GWeiToWei(big.NewInt(int64(effectiveBalancesMap[index]))))
640+
if totalBalance.GreaterThanOrEqual(perks.EffectiveBalancePerDashboard) {
641+
break
642+
}
643+
truncatedValidators = append(truncatedValidators, index)
644+
}
645+
r.Data.Validators = truncatedValidators
646+
return r, nil
647+
}

backend/pkg/api/router.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,10 @@ func addRoutes(hs *handlers.HandlerService, publicRouter, internalRouter *mux.Ro
133133
{http.MethodPost, "/users/me/email", nil, hs.InternalPostUserEmail},
134134
{http.MethodPut, "/users/me/password", nil, hs.InternalPutUserPassword},
135135
{http.MethodGet, "/users/me/dashboards", hs.PublicGetUserDashboards, hs.InternalGetUserDashboards},
136-
{http.MethodPut, "/users/me/notifications/settings/paired-devices/{client_id}/token", nil, hs.InternalPostUsersMeNotificationSettingsPairedDevicesToken},
136+
137+
{http.MethodGet, "/truncated-guest-validator-dashboard", nil, handlers.Handle(http.StatusOK, hs.GetTruncatedGuestValidatorDashboard, allowMocking)},
138+
139+
{http.MethodGet, "/users/me/notifications/settings", hs.PublicGetUserNotificationSettings, hs.InternalGetUserNotificationSettings},
137140

138141
{http.MethodGet, "/users/me/machine-metrics", hs.PublicGetUserMachineMetrics, hs.InternalGetUserMachineMetrics},
139142

backend/pkg/api/types/validator_dashboard.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,3 +451,9 @@ type PostValidatorDashboardValidatorsRequest struct {
451451
type PostValidatorDashboardGroupsRequest struct {
452452
Name string `json:"name"`
453453
}
454+
455+
type TruncatedGuestValidatorDashboardData struct {
456+
Validators []uint64 `json:"validators"`
457+
}
458+
459+
type GetTruncatedGuestValidatorDashboardResponse ApiDataResponse[TruncatedGuestValidatorDashboardData]

frontend/types/api/validator_dashboard.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,3 +406,7 @@ export interface PostValidatorDashboardValidatorsRequest {
406406
export interface PostValidatorDashboardGroupsRequest {
407407
name: string;
408408
}
409+
export interface TruncatedGuestValidatorDashboardData {
410+
validators: number /* uint64 */[];
411+
}
412+
export type GetTruncatedGuestValidatorDashboardResponse = ApiDataResponse<TruncatedGuestValidatorDashboardData>;

0 commit comments

Comments
 (0)